容器启动阶段,主要是将利用某种工具(如XmlBeanDefinitionReader),将XML配置信息,映射为BeanDefinition,并将其注册到相应的BeanDefinitionRegistry。
本文主要探索此阶段,也就是上图AbstractApplicationContext.java的refresh()方法中的finishBeanFactoryInitialization(beanFactory)。下面按照图4-10的流程来探索
顺着红色箭头方向,一路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文件中设置的属性值
继续debug到initializeBean方法,可以看到它里面包括了这几步:
我们先来看看Aware相关接口这一步。
可以看到,当你的Bean实现了上面三种Aware接口的时候,它将分别调用一些set方法,将一些值设置进去。而这些set方法,是你这个Bean在实现Aware接口时,需要重写的。那么你想干什么就干什么,反正已经拿到了对应的值。当然这三个Aware是BeanFactory类型容器里面的,还有几个Aware是ApplicationContext类型容器里面的,并且在下一阶段BeanPostProcessor的前置处理方法中执行。
实现Aware接口的例子,如下图所示:
依旧是这个图,不过我们现在看的是BeanPostProcessor的前置处理方法:
获取所有的BeanPostProcessor这一步,除了我们自己实现的BeanPostProcessor接口,还有容器自带的一些。调用它们的前置处理方法,其中就有我们自己实现的。
实现BeanPostProcessor接口的例子,如下:
又是一个你自己重写的方法,那么又可以为所欲为了,只是它是个无参的。
实现InitializingBean接口的例子如下:
init-method方法又是哪来的?xml文件配置的,然后在类里面自己创建的。
这一步,也是直接利用反射,调用你自己创建的方法
与前置处理没什么两样
此方法和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()方法
在xml文件中配置destroy方法,如图:
destroy方法,同DisposableBean一样,也需要告知容器什么时候执行,所以也需要下面这句:
同样的,我们在destroyMethod方法上打个断点
可以看到,destroyMethod方法和Disposable的destroy方法的执行流程是差不多的。我们再看看DisposableBeanAdapter的destroy方法,点进去。
可以看到destroyMetod的方法,是在destory方法之后执行的
至此,Bean的实例化流程就走完了。下面是debug用到的项目:
public class App implements InitializingBean, FactoryBean
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;
}
}
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();
}
}