一、Spring容器的容器启动阶段和Bean实例化阶段

 

1.1 容器启动阶段

 

  容器启动阶段,主要是将利用某种工具(如XmlBeanDefinitionReader),将XML配置信息,映射为BeanDefinition,并将其注册到相应的BeanDefinitionRegistry。

1.2 Bean实例化阶段

  本文主要探索此阶段,也就是上图AbstractApplicationContext.java的refresh()方法中的finishBeanFactoryInitialization(beanFactory)。下面按照图4-10的流程来探索

 

二、实例化bean对象与BeanWrapper

  顺着红色箭头方向,一路debug下去,到达instantiateBean方法。

  可以看到getInstantiationStrategy()返回的是CglibSubclassingInstantiationStrategy。看到cglib,我们就想到三种代理方式,静态代理,动态代理,以及cglib代理。其中cglib是通过动态字节码来生成目标类的子类,如果不清楚可以百度一下。

 

  Spring容器在内部实现的时候,采用“策略模式(Strategy Pattern)”来决定采用何种方式初始化bean实例。通常,可以通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或者动态生成其子类。默认情况下,容器内部采用的是CglibSubclassingInstantiationStrategy

  容器根据bean对应的BeanDefinition取得实例化信息,结合CglibSubclassingInstantiationStrategy就可以生成对应的bean实例。不过bean实例并不直接返回,而是经过了BeanWrapper包裹一层,再返回BeanWrapper其作用是设置或者获取bean的相应属性值,正是为下一步做准备

 

三、设置对象属性

  继续debug到populateBean方法,此方法就是开始设置对象属性的方法。运行到此方法时,对象的属性如下图,还是null,还未设置

 一旦过了此方法,对象的值便被设置了

可以看到就是xml文件中设置的属性值

 

四、检查Aware相关接口,并设置相关依赖

  继续debug到initializeBean方法,可以看到它里面包括了这几步:

  我们先来看看Aware相关接口这一步。

  可以看到,当你的Bean实现了上面三种Aware接口的时候,它将分别调用一些set方法,将一些值设置进去。而这些set方法,是你这个Bean在实现Aware接口时,需要重写的。那么你想干什么就干什么,反正已经拿到了对应的值。当然这三个Aware是BeanFactory类型容器里面的,还有几个Aware是ApplicationContext类型容器里面的,并且在下一阶段BeanPostProcessor的前置处理方法中执行

 实现Aware接口的例子,如下图所示:

 

五、BeanPostProcessor的前置处理方法

  依旧是这个图,不过我们现在看的是BeanPostProcessor的前置处理方法:

   获取所有的BeanPostProcessor这一步,除了我们自己实现的BeanPostProcessor接口,还有容器自带的一些。调用它们的前置处理方法,其中就有我们自己实现的。

  实现BeanPostProcessor接口的例子,如下:

   

 

六、检查是否是InitializingBean,决定是否调用afterPropertiesSet()方法

  

  又是一个你自己重写的方法,那么又可以为所欲为了,只是它是个无参的。

  实现InitializingBean接口的例子如下:

 

七、检查是否配有自定义的init-method方法

  init-method方法又是哪来的?xml文件配置的,然后在类里面自己创建的。

这一步,也是直接利用反射,调用你自己创建的方法

 

八、BeanPostProcessor的后置处理方法

   与前置处理没什么两样

 

九、是否实现了DisposableBean接口

  此方法和InitializingBean相对应,DisposableBean自定义singleton对象的销毁逻辑,而InitializingBean自定义对象的初始化逻辑。

  此方法只负责singleton类型对象的销毁逻辑,因为Spring容器只负责singleton的生命周期,而不负责prototype。

  此回调方法注册后,返回的对象实例即处于使用状态,只有该对象实例不再被使用的时候,才会执行相关的自定义销毁逻辑,此时通常也就是Spring容器关闭的时候。但Spring容器在关闭之前,不会聪明到自动调用这些回调方法。所以,需要我们告知容器,在哪个时间点来执行对象的自定义销毁方法。

  在ApplicationContext类型的容器中,AbstractApplicationContext为我们提供了registerShutdownHook()方法,该方法底层使用标准的Runtime类的addShutdownHook()方式来调用相应bean对象的销毁逻辑,从而保证在Java虚拟机退出之前,这些singtleton类型的bean对象实例的自定义销毁逻辑会被执行

  我们在自己重写的destroy()方法上打个断点,查看一下它什么时候被执行

  

  可以看到是AbstractApplicationContext的run方法开始的,我们点进去看看。可以看到恰好是registerShutdownHook()方法,通过doClose()方法的一步步调用,终于到了我们自己重写的destroy()方法

  

 

十、是否配置有自定义的destroy方法

  在xml文件中配置destroy方法,如图:

  

destroy方法,同DisposableBean一样,也需要告知容器什么时候执行,所以也需要下面这句:

同样的,我们在destroyMethod方法上打个断点

  可以看到,destroyMethod方法和Disposable的destroy方法的执行流程是差不多的。我们再看看DisposableBeanAdapter的destroy方法,点进去。

可以看到destroyMetod的方法,是在destory方法之后执行的

 

十一、项目结构与文件

  至此,Bean的实例化流程就走完了。下面是debug用到的项目:

public class App implements InitializingBean, FactoryBean<Object>, BeanNameAware, BeanFactoryAware, DisposableBean {
    private String says;

    private App(){
        System.out.println("App.App()");
    }

    public void say(){
        System.out.println("App.say():" + says);
    }

    public String getSays() {
        return says;
    }

    public void setSays(String says) {
        this.says = says;
    }

    /**
     * 在get/set之后,在BeanPostProcessor的before方法之前执行
     */
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("App.setBeanFactory():" + beanFactory);
    }

    /**
     * 在get/set之后,在BeanPostProcessor的before方法之前执行
     */
    public void setBeanName(String name) {
        System.out.println("App.setBeanName():" + name);
    }


    /**
     * 在构造函数和get、set方法之后执行postProcessBeforeInitialization方法
     */


    /**
     * 这个方法是继承InitializingBean接口后,要实现的方法
     * 顾名思义,在属性设置之后进行的一些操作
     */
    public void afterPropertiesSet() throws Exception {
        System.out.println("App.afterPropertiesSet");
    }

    /**
     * 这个方法是spring中通过设置Init-method属性为该方法,然后才会执行。
     * 在afterPropertiesSet之后执行
     */
    public void initMethod(){
        System.out.println("App.initMethod");
    }

    /**
     *  FactoryBean测试
     */
    public Object getObject() throws Exception {
        System.out.println("App.getObject()");
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("test", "GetObject");
        return map;
    }

    public Class<?> getObjectType() {
        return new HashMap().getClass();
    }

    public boolean isSingleton() {
        return true;
    }

    /**
     *在afterPropertiesSet和initMethod方法之后执行postProcessAfterInitialization方法
     */

    /**
     * 在bean销毁阶段执行
     */
    public void destroy() throws Exception {
        System.out.println("App.destroy()");
    }

    public void destroyMethod() {
        System.out.println("App.destroyMethod()");
    }
}
public class BeanFactoryPostProcessorApp implements BeanFactoryPostProcessor {

    private BeanFactoryPostProcessorApp(){
        System.out.println("BeanFactoryPostProcessorApp.BeanFactoryPostProcessorApp()");
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("app");
        beanDefinition.setAttribute("says", "BeanFactoryPostProcessor");
        System.out.println("BeanFactoryPostProcessorApp.postProcessBeanFactory(): " + beanDefinition.getAttribute("says"));
    }
}
public class BeanPostProcessorApp implements BeanPostProcessor {

    /**
     * 如果打印结果出现该字符串,说明进行了初始化
     */
    private BeanPostProcessorApp(){
        System.out.println("BeanPostProcessorApp.BeanPostProcessorApp()");
    }

    /**
     *
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof App){
            ((App) bean).setSays("Before: BeanPostProcessorApp");
            System.out.println("BeanPostProcessorApp.postProcessBeforeInitialization()");
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof App){
            ((App) bean).setSays("After: BeanPostProcessorApp");
            System.out.println("BeanPostProcessorApp.postProcessAfterInitialization()");
        }
        return bean;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
        http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">


    <bean id="app" class="com.me.sourcecode.App" init-method="initMethod" destroy-method="destroyMethod">
        <property name="says" value="App" />
    </bean>

    <bean id="beanPostProcessorApp" class="com.me.sourcecode.BeanPostProcessorApp"></bean>

    <bean id="beanFactoryPostProcessorApp" class="com.me.sourcecode.BeanFactoryPostProcessorApp"></bean>
</beans>
public class FactoryBeanTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringBean.xml");
        Map map = (Map)applicationContext.getBean("app");
        System.out.println("FactoryBeanTest.main():" + map.get("test").toString());
        ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();
    }
}

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐