😉😉 学习交流群:
✅✅1:这是孙哥suns给大家的福利!
✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料
🥭🥭3:QQ群:583783824 📚📚 工作微信:BigTreeJava 拉你进微信群,免费领取!
🍎🍎4:本文章内容出自上述:Spring应用课程!💞💞
💞💞5:以上内容,进群免费领取呦~ 💞💞💞💞
一:BeanPostProcessor分析
1:BeanPostProcessor对于Spring工厂作用
这个事后置处理Bean,这个东西的全称叫做BeanPostProcessor,最主要的作用是对Spring创建的对象进行再加工,这个是Spring工厂中的一个非常有用的高级特性,在Spring底层很多高级的封装的时候都有这个技术的影子,讲了Aop底层的实现的时候,会发现这个技术的价值是非常高的,Spring的Aop底层实现很大的一部分是这个技术进行支撑。
BeanPostProcessor是对Spring的bean工厂进行在加工,Spring工厂创建对象的过程是:Spring获取Spring的核心配置文件之后对spring的核心配置文件进行解析,获取到响应的bean标签会后,通过反射技术调用该类的构造方法,创建该类的实例,第二件事是spring对这个类中的成员变量按照配置进行注入,注入完成之后,调用这个类的初始化方法,对这个类进行一个初始化,这个初始化方法是我们自己定义的,经过这样的一个过程,这个对象就创建并初始化好了,现在就可以通过getBean通过id进行获取这个对象,而这个后置处理bean,是在工厂创建完成这个对象之后,对这个对象进行再次加工,这就是这门技术的意义,那么她是怎么实现对这个工厂创建出来的对象进行再次加工的呢?BeanPostProcessor是一个接口,我们需要把这个对象加工的内容写到接口实现类对应的方法中即可。
在这个接口当中呢有两两个方法,第一个方法是postProcessBeforeInitialization,另外的方法叫after,,这样的接口,当Bean实现了这个接口之后,spring在创建这个对象的过程中,在spring完成调用构造方法创建实例,并依据配置进行注入之后,spring就会调用这个类的postProcessBeforeIntitialzation方法进行一个初始化操作,是通过这个方法中的第一个Object类型bean参数进行传递的,另外一个参数,是这个对象在spring中的id值。在这个方法中通过这两个参数就获取到了这个参数,就可以在方法中对这个实例进行加工了。还要把这个加工好的对象交还给spring,通过参数把这个对象进行处理,交还给spring之后,执行我们配置好的初始化方法,然后将这个对象交给after这个方法,通过这个方法进行一次在加工,加工完毕之后,将这个参数传递个返回给spring。最后在客户处可以通过getBean方法进行获取。
这就是bean引入了BeanPostProcessor这个技术之后的全部的过程分析。后置处理bean的运行原理分析。
对于使用者,我们的作用就是让我们的bean实现这样的接口和接口中的方法,返回的值是Object
具体过程:创建实例-注入-before方法-初始化方法-After方法
有了这两个方法之后呢,实际的过程中,我们我们极少做初始化操作,所以,我们区分这个之前之后,这两个操作就合二为一的,
实际上spring的初始操作使用的很少,所以,这个所谓的前后,也就没有什么前后之分了,两个挨着呢,实现其中的一个方法即可,也就是将代码写入到一个方法中就可以了。选谁,选After就可以了。但是啥也不干你也得有一个return bean得到操作。需要注意的事before这个操作,我们必须return bean对象,这张图使我们必须要理解的内容。
package com.spring;
import com.spring.postBeanProcessor.Catagory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Auther: DaShu
* @Date: 2021/6/24 21:17
* @Description:
*/
public class TestPostBeanProcessor {
@Test
public void test1(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext1.xml");
//-----------------------before-----------------------
//PostBeanProcessorTest{id=10, name='xioajianren'}
//-----------------------before-----------------------
//------------------------init-----------------------
//PostBeanProcessorTest{id=11, name='xiaojianren1'}
//--------------------------init---------------------
//---------------------------after-------------------------------
//PostBeanProcessorTest{id=12, name='xiaojianren2'}
//---------------------------after-------------------------------
}
}
package com.spring.postBeanProcessor;
/**
* @Auther: DaShu
* @Date: 2021/6/24 21:38
* @Description:
*/
public class Catagory {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "PostBeanProcessorTest{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public void init(){
System.out.println("------------------------init-----------------------");
System.out.println(this.toString());
System.out.println("--------------------------init---------------------");
}
}
package com.spring.postBeanProcessor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @Auther: DaShu
* @Date: 2021/6/24 21:04
* @Description:
*/
public class PostBeanProcessorTest implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof com.spring.postBeanProcessor.Catagory){
System.out.println("-----------------------before-----------------------");
System.out.println(bean.toString());
((com.spring.postBeanProcessor.Catagory)bean).setId(11);
((com.spring.postBeanProcessor.Catagory)bean).setName("xiaojianren1");
System.out.println("-----------------------before-----------------------");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("---------------------------after-------------------------------");
((com.spring.postBeanProcessor.Catagory)bean).setId(12);
((com.spring.postBeanProcessor.Catagory)bean).setName("xiaojianren2");
System.out.println(bean.toString());
System.out.println("---------------------------after-------------------------------");
return bean;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id = "catagory" class = "com.spring.postBeanProcessor.Catagory" init-method="init">
<property name="id" value="10"/>
<property name="name" value="xioajianren"/>
</bean>
<bean id = "postBeanProcessorTest" class = "com.spring.postBeanProcessor.PostBeanProcessorTest" />
</beans>
2:BeanPostProcessor对于AOP作用
Spring工厂如何加工创建代理对象
为什么通过原始对象id获取的是代理对象的id值呢?这是aop的核心原理的第二个问题。
Spring的工厂是如何加工和创建这个对象呢?
在spring创建一个对象的时候,spring的工厂可以通过BeanPostProcessor这个工厂来进一步加工这个对象,我们的当时写的案例非常的简单,创建好对象之后,spring工厂调用,在后置BeanPostProcessor当中对这个bean进行赋值,然后将处理后的bean进行返回,当动态代理结合上beanpostprocessor之后,就可以实现这个通过原始的id返回对应的代理对象,其原理呢就是将这个加工代理对象的方法写入到这个后置处理bean中BeanPostProcessor当中的PostProcessorAfterInization这个方法中,然后将代理对象的地址进行返回即可。
我们知道我们很少做这个初始化操作,所以,这个前置处理和后置处理的位置是挨着的,他们的作用是完全一样的,这样的before我们就不用了,直接将bean对象进行返回,交还给spring即可,然后呢,这个所有加工的代理都写在了后置处理的这个方法中,调用的事Proxy.newProxyInstance()这个方法,这里的实现前边都讲过了,然后将创建好的代理对象交还给spring工厂,这样spring工厂就可以通过id获取的事代理对象,这就是通过原始对象的id值获取的事代理对象的加工。