Spring实例化的基本流程和Bean处理器
目录
Spring实例化的基本流程
Bean的处理器
Bean工厂后处理器(BeanFactoryPostProcessor)
动态注册beanDefinition
Bean后处理器(BeanPostProcessor)
Spring实例化的基本流程
在了解处理器之前,要清除spring实例化对象的基本流程:
- 解析spring.xml文件,封装成BeanDefinition
- 将这些BeanDefinition存放到BeanDefinitionMap内
- 遍历Map,得到Bean
- 将Bean存放到singletonObjects
- 通过调用getBean方法得到bean
图解:
Bean的处理器
概念:Spring的后处理器是Spring对外开发的重要扩展点,它允许我们介入到Bean的整个实例化流程中来, 可以动态添加、修改BeanDefinition,动态修改Bean。
Spring主要有两种处理器:一种是Bean工厂后处理器,另一种是Bean后处理器。
区别:
Bean工厂后处理器在BeanDefinitionMap填充完毕,Bean实例化之前执行;
Bean后处理器一般在bean实例化后,填充到单例池SingletonObjectes之前执行。
Bean工厂后处理器(BeanFactoryPostProcessor)
BeanFactoryPostProcessor是一个接口规范,实现该接口的类只需交给Spring容器管理,spring就会调用该接口的方法;
该方法在Bean实例化之前执行,因此可以实现,使用gwtBean获取id为“a”的bean,但返回的结果是B类的bean:
public class MyBfpp implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) throws BeansException {
BeanDefinition a = bf.getBeanDefinition("a");
a.setBeanClassName("com.cc.ClassB");
}
}
使用getBean获取“a”
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("bfpp.xml");
Object bean = app.getBean("a");
System.out.println(bean);
}
}
返回的结果为B类的对象,实现“偷梁换柱”的效果
动态注册beanDefinition
如果有一个类没有交给spring容器处理,但是在工厂后处理器这里手动添加进去,这样也可以使用getBean获取!
步骤:
- 创建一个beanDefinition对象(new RootBeanDefiniton)
- 用该对象设置类的全限定名
- 动态注册到BeanDefinitionMap中 (DefaultListableBeanFactory)
示例:将为被配置的ClassC动态注册到spring中:
public class MyBfpp implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) throws BeansException {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.cc.ClassC");
//注册的方法在DefaultListableBeanFactory里面,所以需要把beanFactory强转一下
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) bf;
defaultListableBeanFactory.registerBeanDefinition("ccc",beanDefinition);
}
}
直接使用getBean("ccc")看是否能获取到对象:
Bean后处理器(BeanPostProcessor)
Bean后处理器也是一个接口,但是它的执行时间是对象创建之后,实现该接口需要重写两个方法,分别在bean的初始化前和初始化后执行:
public class MyBpp implements BeanPostProcessor {
//初始化之前
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("AfterInitialization....");
return bean;
}
//初始化之后
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeforeInitialization");
return bean;
}
}
注意:想要看到打印结果,需要将一些类交给spring管理才会执行这些方法!
示例:
写了一个A类和B类交给spring容器管理,并且使用init-method调用初始化方法:
<bean class="com.cc.ClassA" id="a" init-method="aInit"></bean>
<bean class="com.cc.ClassB" id="b" init-method="bInit"></bean>
可以看到执行顺序为 postProcessBeforeInitialization -> 初始化方法 -> postProcessAfterInitialization
那么现在可以完善一下spring实例化对象的基本流程图: