Bean的实例化过程
一、Spring容器的容器启动阶段和Bean实例化阶段 1.1 容器启动阶段 容器启动阶段,主要是将利用某种工具(如XmlBeanDefinitionReader),将XML配置信息,映射为BeanDefinition,并将其注册到相应的BeanDefinitionRegistry。1.2 Bean实例化阶段 本文主要探索此阶段,也就是上图Abstract...
一、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();
}
}
更多推荐
所有评论(0)