今天在群里面看到了一个很有趣的问题。那就是Spring IOC的执行顺序问题。知道IOC初始化顺序的朋友都应该知道,Spring IOC的执行顺序:
- 先执行BeanPostProcessor.postProcessBeforeInitialization方法。
- 然后执行InitializingBean.afterPropertiesSet方法。
- 最后再执行BeanPostProcessor.postProcessAfterInitialization方法。
也就是说InitializingBean.afterPropertiesSet的执行顺序是在BeanPostProcessor的before和after方法之间执行。
但是群里面的那个朋友遇到了这样的问题。就是InitializingBean.afterPropertiesSet的执行顺序是在BeanPostProcessor的before和after方法之前执行。那么这个是不是就是Spring IOC的生命周期相矛盾呢?
首先我再现一下这个问题。
1、问题复现
Bean类同时实现BeanPostProcessor与InitializingBean.
Bean.java
@Component
public class Bean implements BeanPostProcessor, InitializingBean {
public void afterPropertiesSet() throws Exception {
System.out.println("-----------------------invoke InitializingBean method afterPropertiesSet");
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------------------invoke BeanPostProcessor method postProcessBeforeInitialization");
return null;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------------------invoke BeanPostProcessor method postProcessAfterInitialization");
return null;
}
}
测试类,用于加载配置的Bean文件。
Test.java
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(Bean.class);
configApplicationContext.getBean(Bean.class);
}
}
运行结果:
在图片中我们可以看到:
InitializingBean.afterPropertiesSet先于BeanPostProcessor.postProcessBeforeInitialization执行。这就和Spring IOC的生命周期相悖。
那么下面就来分析一下为什么会出现这种情况:
2、问题的来源
我们知道,当使用BeanPostProcessor的时候,Spring会先注册这个对象。要注册这个对应其实就是把它纳入到Spring容器的管理中,就会调用getBean方法。
其实看到这里大家就应该明白了。
- 当注册BeanPostProccessor的时候会调用getBean方法,那个时候BeanPostProcess并不生效,所以只会调用InitializingBean的afterPropertiesSet方法,
- 然后再注册了这个BeanPostProcessor就会调用它的postProcessBeforeInitialization和postProcessAfterInitialization。
- 当你再次使用getBean方法调用的时候这个时候,Spring容器里面已经存在了这个Bean对象,它就会直接从容器里面拿,就不需要走到后面的实例化bean,所以不会出现InitializingBean的方法,也不会出现BeanPostProcessor的处理方法。
3、问题的思考
细想一下,其实我们这个Bean这个类即实现了BeanPostProcessor,又实现了InitializingBean。当我们实现BeanPostProcessor的时候是希望这个对象是作为Spring IOC容器功能的扩展,而实现InitializingBean是把这个对象当成一个普通Bean。明显这个对象在这里是有二个角色。这里就涉及到面向对象设计的一个重要的原则 – 单一职责原则。所以我们在设计功能的时候,一定要考虑面向对象设计的原则。