什么是BeanPostProcessor接口?
spring BeanPostProcessor接口可以在Bean初始化操作之前和初始化操作之后做一些有趣的事情。例如属性注入(AutowiredAnnotationBeanPostProcessor)
例如AOP代理类生成(AnnotationAwareAspectJAutoProxyCreator)
总之,他的作用是非常大,能适应的场景也是非常多。
BeanPostProcessor系的接口列表
接口列表 |
BeanPostProcessor |
InstantiationAwareBeanPostProcessor |
SmartInstantiationAwareBeanPostProcessor |
该系列接口都是在BeanPostProcessor基础上扩展,只是某些方法产生了细分,大方向上与BeanPostProcessor一致。
为什么会失效?
失效原因1:BeanPostProcessor不是Bean或注册为Bean的时机不对
public class Bean3 {
}
public class BeanPostProcessorDemo implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"初始化之前");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"初始化之后");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
//有输出示例
public static void main( String[] args )
{
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(Bean3.class);
ac.register(BeanPostProcessorDemo.class);
ac.refresh();
ac.getBean(Bean3.class); //运行有输出,一切正常
}
//无输出示例
public static void main( String[] args )
{
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(Bean3.class);
ac.refresh(); //容器初始化
ac.register(BeanPostProcessorDemo.class); //在容器初始化之后注册bean
ac.getBean(Bean3.class); //运行无输出,时机已过,即使注册为Bean也无效
}
失效原因2:没有添加
//代码接上例
//新获取一个Bean,测试是否有效
public static void main( String[] args )
{
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(Bean3.class);
ac.refresh();
ac.register(BeanPostProcessorDemo.class);
//新注册然后再获取一个bean来测试,因为Bean3被容器初始化了,但是BeanPostProcessor还没注册
//可能是这个原因导致的。所以开启一个新的Bean来测试
ac.register(Bean4.class);
Object o = ac.getBean(Bean4.class);
//新注册一个bean,在获取 还是无输出,证明BeanPostProcessor要运行可能不仅是要求为Bean
//可能还有其他的要求
}
//最终示例
public static void main( String[] args )
{
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(Bean3.class);
ac.refresh();
ac.register(BeanPostProcessorDemo.class);
//添加BeanPostProcessor到集合中
ac.getBeanFactory().addBeanPostProcessor(ac.getBean(BeanPostProcessorDemo.class));
ac.register(Bean4.class);
Object o = ac.getBean(Bean4.class);
//有输出,证明BeanPostProcessor要运行的关键是需要追加addBeanPostProcessor方法内
}
BeanPostProcessor初始化,运行解析
初始化原理
//AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
//省略若干行
registerBeanPostProcessors(beanFactory);
//省略若干行
}
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//获取所有BeanPostProcessor的Bean
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//省略若干行代码
//把遍历到的BeanPostProcessor添加到集合中,至此,BeanPostProcessor初始化完毕
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
//省略若干行代码
}
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
运行原理
//AbstractAutowireCapableBeanFactory.java
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
//运行原理就非常简单了,任何获取Bean的操作,都会执行
//其中getBeanPostProcessors()方法用来获取addBeanPostProcessor的集合
//然后就是一个遍历责任链了。从这里一个侧面可以看出,如果能实例化后添加到
//addBeanPostProcessor方法内,那么不是Bean也是OK的。
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
结论
如果初始化时机不正确,则需要手动矫正一下(通过addBeanPostProcessor方法来追加)
为什么要产生BeanPostProcessor初始化时机不对的情况,这样的场景为什么会发生?
其实这样的例子比比皆是,不是所有Bean都能在spring 容器初始化之前确定。
如果BeanPostProcessor是动态注册的,或者其他Bean也是动态注册的,则需要这样处理。很多时候,bean都是通过编程动态产生的。例如要根据远程配置文件的信息,动态生成数据库连接池Bean等等。这些场景都真实存在。