为了便于初学者理解,这里采用一个仿Spring源码的开源项目作为例子,mini-spring (如果链接失效私信我哦~)
目录
前言
由于我们研究的是源码,且纯概念的东西过于抽象,我们这里用一个实例来作为载体。看看它在执行过程中是如何体现ApplicationContext的自动识别功能。
众所周知,BeanFactoryPostProcessor是在所有BeanDefintion加载完成后,但在bean实例化之前,提供修改BeanDefinition属性值的机制。
BeanPostProcessor是用于修改实例化后的bean的修改扩展点
在开始之前我们在这里先留个问题?
什么是ApplicationContext?
在这里我们暂且先按下步表!
一下是一个测试类:通过获取Person和car两个对象的bean来体现它的自动识别功能。
public class ApplicationContextTest {
@Test
public void testApplicationContext() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
Person person = applicationContext.getBean("person", Person.class);
System.out.println(person);
//name属性在CustomBeanFactoryPostProcessor中被修改为ivy
assertThat(person.getName()).isEqualTo("ivy");
Car car = applicationContext.getBean("car", Car.class);
System.out.println(car);
//brand属性在CustomerBeanPostProcessor中被修改为lamborghini
assertThat(car.getBrand()).isEqualTo("lamborghini");
}
}
在以上类中我们第一步要创建 ClassPathApplicationContext对象。那它又是什么呢?我们来看一下它和其他接口/类的依赖关系
其实由此也就引出了我们今天的主角ApplicationContext!
事已至此,我们解决第一个问题。
什么是ApplicationContext接口?
要了解一个接口我们要搞清楚他的上下游关系,这样才能知道它从哪里来,要到哪里去?
我们看图说话
上游关系:
我们要研究的接口上层继承了Bean工厂接口和资源加载接口,由此可以推理出,我们的目标接口中,一定有的功能是,通过加载对应资源进行bean的创建
下游关系:
由此观之,ApplicationContext接口是我们在第一步创建ClassPathXmlApplicationContext 对象时的重要接口。
接下来我们开始讲BeanFactoryPostProcessor和BeanPostProcessor如何自动识别目标Bean
第一步:创建ClassPathXmlApplicationContext
第二步:执行ClassPathXmlApplicationContext 构造器
第三步:调用其父类方法refresh()
在refreshBeanFactory()方法中,会将Bean的信息加载到BeanDefinition中,包括所属类型(这里需要留意一下)
第四步:调用invokeBeanFactoryPostProcessors()方法
执行BeanFactoryPostProcessor接口中实现的方法
BeanFactoryPostProcessor的自动识别
注意:从这一步开始体现出自动识别(即通过反射去获取有BeanPostProcessor类型的bean)
这里的BeanDefinition为啥会被标记为BeanPostProcessor,因为再xml文件中早就标记好了!!!
在第三步:调用其父类方法refresh()
中的第一个方法就是将xml文件中的信息放入BeanDefinition,这里要取出来做比对
到这里,BeanFactoryPostProcessor已经自动根据BeanDefinition的信息对目标Bean进行了特定属性的修改
BeanPostProcessor的自动识别同上
为什么要加入呢?在后续创建Bean的时候会取出来
在初始化之前执行
至此,我们已经完全追完BeanFactoryPostProcessor和BeanPostProcessor相关的源码了