Spring IOC 初始化顺序问题

今天在群里面看到了一个很有趣的问题。那就是Spring IOC的执行顺序问题。知道IOC初始化顺序的朋友都应该知道,Spring IOC的执行顺序:

  1. 先执行BeanPostProcessor.postProcessBeforeInitialization方法。
  2. 然后执行InitializingBean.afterPropertiesSet方法。
  3. 最后再执行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);
    }

}

运行结果:

Spring IOC 初始化顺序问题_第1张图片

在图片中我们可以看到:
InitializingBean.afterPropertiesSet先于BeanPostProcessor.postProcessBeforeInitialization执行。这就和Spring IOC的生命周期相悖。

那么下面就来分析一下为什么会出现这种情况:

2、问题的来源

我们知道,当使用BeanPostProcessor的时候,Spring会先注册这个对象。要注册这个对应其实就是把它纳入到Spring容器的管理中,就会调用getBean方法。

Spring IOC 初始化顺序问题_第2张图片

其实看到这里大家就应该明白了。

  1. 当注册BeanPostProccessor的时候会调用getBean方法,那个时候BeanPostProcess并不生效,所以只会调用InitializingBean的afterPropertiesSet方法,
  2. 然后再注册了这个BeanPostProcessor就会调用它的postProcessBeforeInitialization和postProcessAfterInitialization。
  3. 当你再次使用getBean方法调用的时候这个时候,Spring容器里面已经存在了这个Bean对象,它就会直接从容器里面拿,就不需要走到后面的实例化bean,所以不会出现InitializingBean的方法,也不会出现BeanPostProcessor的处理方法。

3、问题的思考

细想一下,其实我们这个Bean这个类即实现了BeanPostProcessor,又实现了InitializingBean。当我们实现BeanPostProcessor的时候是希望这个对象是作为Spring IOC容器功能的扩展,而实现InitializingBean是把这个对象当成一个普通Bean。明显这个对象在这里是有二个角色。这里就涉及到面向对象设计的一个重要的原则 – 单一职责原则。所以我们在设计功能的时候,一定要考虑面向对象设计的原则。

你可能感兴趣的:(Spring,Framework)