不你不了解Spring实例化bean的时候做了什么

40次阅读

共计 12876 个字符,预计需要花费 33 分钟才能阅读完成。

Spring 加载 bean 的时候构造函数什么时候调用、@PostConstruct 什么时候调用、实现了 BeanPostProcessor 接口的 bean 中的 postProcessAfterInitialization 和 postProcessBeforeInitialization 什么时候调用?你是否清楚呢?如果清楚的话可以直接忽略该篇文章!!!

最近来了几个新人,被问了一个和 bean 生命周期相关的一个知识点,解决新人的问题后自己再写了一个 demo,目的是为了清晰的描述整个 bean 的生命周期。

注意注意,以下 demo 有五个类,可能会引起部分人不适,建议可以直接跳到最后看 最终总结,或者自己下载源码运行下。
demo 地址:https://github.com/wiatingpub…

给出一个 demo

首先给出一个实现了 BeanFactoryPostProcessor 的类,目的是为了比较清晰的看出 postProcessBeanFactory 接口被调用的时间点。

/**
 * BeanFactoryPostProcessor 是 bean 工厂的处理器
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {public MyBeanFactoryPostProcessor() {super();
        System.out.println("【BeanFactoryPostProcessor】实现类 postProcessBeanFactory 的构造函数");
    }

    // 允许我们在工厂里所有的 bean 被加载进来后但是还没初始化前,对所有 bean 的属性进行修改也可以 add 属性值,该操作在对应 bean 的构造函数执行前
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out
                .println("【BeanFactoryPostProcessor.postProcessBeanFactory】,来自 MyBeanFactoryPostProcessor");
        // 获取到 Spring 中所有的 beanName
        String[] beanStr = arg0.getBeanDefinitionNames();
        // 循环打印
        for (String beanName : beanStr) {System.out.print("bean name:" + beanName + ";");
        }

        System.out.println();}
}

这里给出一个实现了 BeanPostProcessor 的类,目的是为了看出 postProcessAfterInitialization、postProcessBeforeInitialization 调用的时间点。/**
 * 完成 bean 实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理则要实现接口 BeanPostProcessor
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {public MyBeanPostProcessor() {super();
        System.out.println("【MyBeanPostProcessor】BeanPostProcessor 实现类的构造函数");
    }

    // 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的业务
    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) {
            System.out
                    .println("【BeanPostProcessor.postProcessAfterInitialization】来自 MyBeanPostProcessor,beanName:" + arg1);
        }
        return arg0;
    }

    // 实例化、依赖注入、初始化后完成一些定制的业务
    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) {
            System.out
                    .println("【BeanPostProcessor.postProcessBeforeInitialization】来自 MyBeanPostProcessor,beanName:" + arg1);
        }
        return arg0;
    }
}

这里给出继承了 InstantiationAwareBeanPostProcessorAdapter 的子类,目的是为了看出 postProcessBeforeInitialization、postProcessAfterInitialization、postProcessPropertyValues 被调用的时间点。

/**
 * 适配器类,基类是 BeanPostProcessor 的实现类
 */
@Component
public class MyInstantiationAwareBeanPostProcessor extends
        InstantiationAwareBeanPostProcessorAdapter {public MyInstantiationAwareBeanPostProcessor() {super();
        System.out
                .println("【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter 实现类的构造函数");
    }

    // 接口方法、实例化 Bean 之前调用
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);

        }
        return bean;
    }

    // 接口方法、实例化 Bean 之后调用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);
        }

        return bean;
    }

    // 接口方法、设置某个属性时调用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
                                                    PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException {if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自 MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);
        }

        return pvs;
    }

这个就牛逼了,直接交给 applicationContext.xml 注入并且实现了 BeanFactoryAware, BeanNameAware,InitializingBean,DisposableBean 四个接口类,目的是为了清晰的看出以下好几个接口被调用的时间点。

public class TestBeanA implements BeanFactoryAware, BeanNameAware,
        InitializingBean, DisposableBean {

    private String name;
    private String address;
    private int phone;

    private BeanFactory beanFactory;
    private String beanName;

    @PostConstruct
    public void init() {System.out.println("【TestBeanA.@PostConstruct】");
    }

    public TestBeanA() {System.out.println("【TestBeanA. 默认构造器】");
    }

    public TestBeanA(String name) {System.out.println("【TestBeanA. 带参构造器】");
    }

    public String getName() {return name;}

    public void setName(String name) {this.name = name;}

    public String getAddress() {return address;}

    public void setAddress(String address) {this.address = address;}

    public int getPhone() {return phone;}

    public void setPhone(int phone) {this.phone = phone;}

    @Override
    public String toString() {
        return "TestBeanA [address=" + address + ", name=" + name + ", phone="
                + phone + "]";
    }

    // 这是 BeanFactoryAware 接口方法
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out
                .println("【BeanFactoryAware.setBeanFactory】来自 TestBeanA");
        this.beanFactory = arg0;
    }

    // 这是 BeanNameAware 接口方法
    @Override
    public void setBeanName(String arg0) {System.out.println("【BeanNameAware.setBeanName】来自 TestBeanA");
        this.beanName = arg0;
    }

    // 这是 InitializingBean 接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out
                .println("【InitializingBean.afterPropertiesSet】来自 TestBeanA");
    }

    // 这是 DiposibleBean 接口方法
    @Override
    public void destroy() throws Exception {System.out.println("【DiposibleBean.destory】来自 TestBeanA");
    }

    // 通过 <bean> 的 init-method 属性指定的初始化方法
    public void myInit() {System.out.println("【TestBeanA.myInit】");
    }

    // 通过 <bean> 的 destroy-method 属性指定的初始化方法
    public void myDestory() {System.out.println("【TestBeanA.destroy-method】");
    }
}

TestBeanB 的作用比较简单,为了看出内部数据成员有其他容器 Bean 的时候 Spring 是如何加载 bean 的。

@Component
public class TestBeanB {

    @Autowired
    private TestBeanA testBeanA;

    public TestBeanB() {System.out.println("【TestBeanB. 默认构造器】");
    }
}

这个是启动类。

@SpringBootApplication
@ImportResource(locations = {"classpath:applicationContext.xml"})
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);
    }
}

虽然使用的是 SpringBoot,这里还使用 xml 是为了看看 init-method 和 destroy-method 的调用时间。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="testBeanA" class="com.example.demo.bean.TestBeanA" init-method="myInit" destroy-method="myDestory">
        <property name="name" value="关注微信公众号 饭说编程"/>
    </bean>
</beans>

很长很长的代码算是都给出来了,接下来看下运行后给出的结果

【BeanFactoryPostProcessor】实现类 postProcessBeanFactory 的构造函数【BeanFactoryPostProcessor.postProcessBeanFactory】,来自 MyBeanFactoryPostProcessor【MyBeanPostProcessor】BeanPostProcessor 实现类的构造函数【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter 实现类的构造函数【TestBeanB. 默认构造器】【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanB【TestBeanA. 默认构造器】【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanA【BeanNameAware.setBeanName】来自 TestBeanA【BeanFactoryAware.setBeanFactory】来自 TestBeanA【BeanPostProcessor.postProcessBeforeInitialization】来自 MyBeanPostProcessor,beanName:testBeanA【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanA【TestBeanA.@PostConstruct】【InitializingBean.afterPropertiesSet】来自 TestBeanA【TestBeanA.myInit】【BeanPostProcessor.postProcessAfterInitialization】来自 MyBeanPostProcessor,beanName:testBeanA【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanA【BeanPostProcessor.postProcessBeforeInitialization】来自 MyBeanPostProcessor,beanName:testBeanB【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanB【BeanPostProcessor.postProcessAfterInitialization】来自 MyBeanPostProcessor,beanName:testBeanB【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanB【DiposibleBean.destory】来自 TestBeanA【TestBeanA.destroy-method】

貌似又是一段看完头晕脑胀的恶心代码,不过不方不方,直接进入分析阶段,跟着分析入手就简单多了。

通过结果分析

首先从

【BeanFactoryPostProcessor】实现类 postProcessBeanFactory 的构造函数【BeanFactoryPostProcessor.postProcessBeanFactory】,来自 MyBeanFactoryPostProcessor【MyBeanPostProcessor】BeanPostProcessor 实现类的构造函数【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter 实现类的构造函数

可以看出执行顺序是:

  • 调用 postProcessBeanFactory 实现类的构造函数

BeanFactoryPostProcessor 是 bean 工厂的处理器

  • 调用 postProcessBeanFactory 实现类的 postProcessBeanFactory 实现函数

postProcessBeanFactory 函数允许我们在工厂里所有的 bean 被加载进来后但是还没初始化前,对所有 bean 的属性进行修改也可以 add 属性值

  • 调用 BeanPostProcessor 实现类的构造函数

完成 bean 实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理则要实现接口 BeanPostProcessor

  • 调用 InstantiationAwareBeanPostProcessorAdapter 实现类的构造函数

适配器类,基类是 BeanPostProcessor 的实现类

再从

【TestBeanB. 默认构造器】【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanB

可以看到,此处 spring 容器先扫描到了 TestBeanB,因此调用顺序是

  • TestBeanB 的默认构造器【无参构造器】
  • 调用 InstantiationAwareBeanPostProcessorAdapter 实现类的 postProcessPropertyValues 接口

postProcessPropertyValues 在接口方法、设置某个属性时调用,通过实验看到实例化一个 Bean 的时候也会调用该接口方法

之后实例化 TestBeanB 的时候发现内部注入了 TestBeanA,因此 Spring 转而实例化 TestBeanA。

接下来看到的是 TestBeanA 的实例化过程中调用的顺序

【TestBeanA. 默认构造器】【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanA【BeanNameAware.setBeanName】来自 TestBeanA【BeanFactoryAware.setBeanFactory】来自 TestBeanA【BeanPostProcessor.postProcessBeforeInitialization】来自 MyBeanPostProcessor,beanName:testBeanA【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanA【TestBeanA.@PostConstruct】【InitializingBean.afterPropertiesSet】来自 TestBeanA【TestBeanA.myInit】【BeanPostProcessor.postProcessAfterInitialization】来自 MyBeanPostProcessor,beanName:testBeanA【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
  • 调用了 TestBeanA 的默认构造器
  • 调用 InstantiationAwareBeanPostProcessorAdapter 实现类的 postProcessPropertyValues 接口
  • 调用 BeanNameAware 的 setBeanName 接口

可以从源码看到 TestBeanA 实现了接口 BeanNameAware

  • 调用 BeanFactoryAware 的 setBeanFactory 接口

可以从源码看到 TestBeanA 实现了接口 BeanFactoryAware

  • 调用 BeanPostProcessor 的 postProcessBeforeInitialization 接口
  • 调用 InstantiationAwareBeanPostProcessorAdapter 的 postProcessBeforeInitialization 接口
  • 调用 TestBeanA 中注解了 @PostConstruct 的函数
  • 调用了 InitializingBean 的 afterPropertiesSet 接口

可以从源码看到 TestBeanA 实现了接口 InitializingBean

  • 调用了 TestBeanA 的 myInit 接口

可以看到该 init-method 接口是在 applicationContext 中 init-method 配置上的

  • 调用 BeanPostProcessor 实现类的 postProcessAfterInitialization 接口
  • 调用 InstantiationAwareBeanPostProcessorAdapter 子类的 postProcessAfterInitialization 接口

等 TestBeanA 实例化结束后,则继续 TestBeanB 的实例化路程

【BeanPostProcessor.postProcessBeforeInitialization】来自 MyBeanPostProcessor,beanName:testBeanB【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanB【BeanPostProcessor.postProcessAfterInitialization】来自 MyBeanPostProcessor,beanName:testBeanB【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自 MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
  • 调用 BeanPostProcessor 实现类的 postProcessBeforeInitialization 接口
  • 调用 InstantiationAwareBeanPostProcessorAdapter 子类的 postProcessBeforeInitialization 接口
  • 调用 BeanPostProcessor 实现类的 postProcessAfterInitialization 接口
  • 调用 InstantiationAwareBeanPostProcessorAdapter 子类的 postProcessAfterInitialization 接口

最后

【DiposibleBean.destory】来自 TestBeanA【TestBeanA.destroy-method】
  • 调用 DiposibleBean 实现类的 destory 接口

TestBeanA 实现了 DiposibleBean 接口,实现了 destroy 接口

  • 调用 TestBeanA 的 myDestory 函数

可以看到该 myDestory 接口是在 applicationContext 中 destroy-method 配置上的。

最终总结

【超重点,面试回答模板,老牛逼了】

  • 如果有 bean 实现了 BeanFactoryPostProcessor 接口类,则会实例化该 bean,并且调用默认构造器,然后调用 postProcessBeanFactory 接口
  • 如果有 bean 实现了 BeanPostProcessor 接口类,则会先实例化该 bean,同样调用默认构造器
  • 如果有 bean 继承了 InstantiationAwareBeanPostProcessorAdapter 类,则会先实例化该 bean,同样调用默认构造器

之后真正进入一个 bean 的生命周期过程

  • 先调用 bean 的默认构造函数
  • 如果有 bean 继承了 InstantiationAwareBeanPostProcessorAdapter 类,此刻会调用 postProcessPropertyValues 函数
  • 如果这个 bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName 方法,此处传递的就是 applicationContext.xml 配置文件中 Bean 的 id 值
  • 如果这个 bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory,传递的是 Spring 工厂自身
  • 如果存在其他 bean 实现了 BeanPostProcessor 接口,将会调用 postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 经常被用作是 Bean 内容的更改,并且由于这个是在 Bean 初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
  • 如果存在其他 bean 继承了 InstantiationAwareBeanPostProcessorAdapter 类,则会调用 postProcessBeforeInitialization 接口
  • 如果这个 bean 中有函数加了 @PostConstruct 注解,则该函数会在此刻被调用
  • 如果这个 bean 实现了 InitializingBean 接口重写了 afterPropertiesSet 方法,该方法会在此刻被调用
  • 如果这个 bean 在 Spring 配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
  • 如果存在其他 bean 实现了 BeanPostProcessor 接口,将会调用 postProcessAfterInitialization(Object obj, String s)方法
  • 如果存在其他 bean 继承了 InstantiationAwareBeanPostProcessorAdapter 类,则会调用 postProcessAfterInitialization 接口

走到这一步以后就可以应用这个 Bean 了,而这个 Bean 是一个 Singleton 的,虽然在 Spring 配置文件中也可以配置非 Singleton,这里不做赘述。

走入销毁阶段

  • 当 bean 不再需要时,会经过清理阶段,如果这个 bean 实现了 DisposableBean 接口,会调用其实现的 destroy()方法;
  • 如果这个 bean 的 applicationContext.xml 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。

Java 源码分析、go 语言应用、微服务,更多干货欢迎关注公众号:

正文完
 0