Spring的后处理器
Spring的后处理器是Spring对外开放的重要拓展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:
1、BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;
2、BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。
由此,通过Bean工厂后处理器,我们可以在<bean>标签被录入信息完毕后修改指定的bean信息,甚至自己添加bean信息,这样就绕过了xml配置的环节。
Bean工厂后处理器——BeanFactoryPostProcessor
例1:利用BeanDefinition的getBeanDefinition方法动态修改BeanDefinition
xml文件中beanId为userService对应的bean实例为UserServiceImpl
定义一个配置类实现BeanFactoryPostProcessor接口,修改id为userSerivce的BeanDefinition,将其对应的实例修改为UserDaoImpl
getBean去拿userSerive的实例
但是拿到的却是UserDaoImpl实例
例2:利用BeanDifinition的子类——RootBeanDefinition动态注册BeanDefinition
这里第三行的被强转的beanFactory是形参。
BeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.itheima.dao.impl.PersonDaoImpl");
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)beanFactory;
defaultListableBeanFactory.registerBeanDefinition("personDao",beanDefinition);
当然这个配置类得去xml中配置,Spring不能自己识别到这个配置类的
Spring也提供了BeanDefinitionRegistryPostProcessor接口专门用于注册BeanDefinition操作。
同样的,要去xml中配置这个配置类
Bean工厂后处理器
Bean后处理器
不同于Bean工厂后处理器,Bean后处理器开始于Bean被实例化后,并在实例化的Bean被缓存到单例池之前执行,中间经过Bean的初始化过程,包括:属性的填充、初始方法init的执行等,其中一个对外拓展的点接口BeanPostProcessor被称为Bean后处理,实现了该接口并被容器管理的配置类会在流程节点上被Spring自动调用。
实现BeanPostProcessor接口的配置类需要主动覆写两个方法,因为下面两个方法有@Nullable注解,所以要我们手动覆写:
porstProcessBeforeInitialization方法在属性注入完毕 后,init初始化方法执行之前被回调;
postProcessAfterInitialization方法在init初始化方法执行之后,被添加到单例池singletonObjects之前被回调。
Bean后处理器快速入门
在init方法执行之前,把bean拿出来判断是不是UserDaoImpl,是的话就为其注入属性username=haohao
xml文件中配置Bean后处理器
Bean容器初始化
案例:时间日志功能增强
定义一个增强类实现BeanPostProcessor接口
public class TimeLogBeanPostProcessor implements BeanPostProcessor {
//重写after方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception{
//使用动态代理对目标Bean进行增强,返回proxy对象,进而存储到单例池singletonObjects中
Object beanProxy = Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
//在这里对目标Bean进行增强
//1.输出开始时间
System.out.println("方法:" + method.getName() + "-结束时间:" + new Date());
//2.执行目标方法
Object result = method.invoke(bean, args);
//3.输出结束时间
System.out.println("方法:" + method.getName() + "-结束时间:" + new Date());
return result;
}
);
return beanProxy;//返回增强后的目标Bean
}
}
在xml中配置一个用于验证的Bean,配置我们的增强类 :
用于验证的Bean:
测试代码:
测试结果:
该增强类利用动态代理,对所有的Bean的所有方法的执行前后都增强了打印时间日志的功能。
继续完善实例化基本流程图
以下是BeanPostProcessor在SpringBean的实例化过程中的体现
大体上,在ApplicationContext容器的环境下,在xml文件加载后,所有的<bean>标签内容都封装成BeanDefinition并将BeanDefinition存入beanDefinitionMap中,然后遍历beanDefinitionMap将bean实例化并存入singletonObjects单例池中,当调用getBean()时从单例池中去拿对象。
在学习完Spring的后处理器后我们可以知道,在遍历beanDefinitionMap拿出beanDefinition后,要先经过BeanFactoryPostProcessor(Bean工厂后处理器),然后通过反射变成一个对象Obj,在对象进入单例池之前,还要经过BeanPostProcessor(Bean后处理器)的before和after方法,最后才进入单例池中。