5、Mini-spring 应用上下文ApplicationContext
前言:
上一篇文章,我们分析实现了BeanFactoryPostProcessor
和BeanPostProcessor
两个重要级接口,这两个接口都是spring提供的容器扩容机制,他们的区别是BeanFactoryPostProcessor
接口是在bean实例化之前修改beanDefinition信息,BeanPostProcessor
是在bean实例化之后对bean做修改,而且BeanPostProcessor是后面实现AOP的关键。这一节我们将引入ApplicationContext
,ApplicationContext
能自动识别BeanFactoryProcessor
和BeanPostProcessor
,这样就可以通过直接在xml中进行配置,不用手动添加到BeanFactory了。
ApplicationContext:
ApplicationContext是Spring中较BeanFactory更为先进的IOC容器,ApplicationContext除了拥有BeanFactory的所有功能外,还支持特殊类型bean如上一节中的BeanFactoryPostProcessor和BeanPostProcessor的自动识别、资源加载、容器事件和监听器、国际化支持、单例bean自动初始化等。
BeanFactory是spring的基础设施,面向spring自身;而ApplicationContext面向spring的使用者,应用场合使用ApplicationContext。
具体实现:
我们先来看几个新增的几个应用上下文相关接口类的关系。
可以看到最上层的是ApplicationContext
,中间多个抽象类和接口,最下层的是ClassPathXmlApplicationContext
,Xml文件的应用上下文。我们就是最终通过ClassPathXmlApplicationContext
来完成我们之前所有的一系列操作,加载xml文件中的内容,并且对bean实例化前后进行扩展操作。
直接从测试Demo看,我们之前所有的先创建beanFactory对象,再加载xml文件,然后手动去创建BeanFactoryPostProcessor/BeanPostProcessor实例,再调用各自的方法这些步骤,都省去了,简化成了一行代码就是ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
测试:
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");
}
}
来看下ClassPathXmlApplicationContext实例化做了什么事情,可以看到传递完xml文件参数后,接着调用了另一个构造器,配置了对应的文件,然后调用了refresh()方法
/**
* xml文件的应用上下文
*
*/
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
private String[] configLocations;
/**
* 从xml文件加载BeanDefinition,并且自动刷新上下文
*
* @param configLocation xml配置文件
* @throws BeansException 应用上下文创建失败
*/
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation});
}
/**
* 从xml文件加载BeanDefinition,并且自动刷新上下文
*
* @param configLocations xml配置文件
* @throws BeansException 应用上下文创建失败
*/
public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {
this.configLocations = configLocations;
refresh();
}
protected String[] getConfigLocations() {
return this.configLocations;
}
}
refresh()方法:
我们重点分析refresh()方法。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException {
//创建BeanFactory,并加载BeanDefinition
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//在bean实例化之前,执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
//BeanPostProcessor需要提前与其他bean实例化之前注册
registerBeanPostProcessors(beanFactory);
//提前实例化单例bean
beanFactory.preInstantiateSingletons();
}
/**
* 创建BeanFactory,并加载BeanDefinition
*
* @throws BeansException
*/
protected abstract void refreshBeanFactory() throws BeansException;
/**
* 在bean实例化之前,执行BeanFactoryPostProcessor
*
* @param beanFactory
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
/**
* 注册BeanPostProcessor
*
* @param beanFactory
*/
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
public String[] getBeanDefinitionNames() {
return getBeanFactory().getBeanDefinitionNames();
}
public abstract ConfigurableListableBeanFactory getBeanFactory();
}
refreshBeanFactory()
refresh()方法干的第一件事情,就是创建BeanFactory工厂,然后加载BeanDefinition,我们看下这个方法的具体内部实现。首先创建了个DefaultListableBeanFactory,接着将这个beanFactory作为参数,然后调用loadBeanDefinitions(beanFactory)
;
protected final void refreshBeanFactory() throws BeansException {
DefaultListableBeanFactory beanFactory = createBeanFactory();
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
接着看loadBeanDefinitions(beanFactory)
,这里需要着重理解下,还记得上上节,我们在实现资源加载器加载xml的时候是怎么调用的吗,可以去翻一翻第三节中的内容,当时我们是直接传入beanFactory。
传入beanFactory后,调用父类另一个构造器,将默认的查找资源DefaultResourceLoader传入。、
回到这里,现在的调用,是将this作为第二个参数,this是什么,this就是当前对象AbstractXmlApplicationContext
。为什么这里可以直接将this作为资源加载器ResourceLoader呢,其实是因为抽象的应用上下文也同时继承了DefaultResourceLoader
。这里的类关系比较复杂,所以在自己看的时候要仔细分析各个类的职责。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
String[] configLocations = getConfigLocations();
if (configLocations != null) {
beanDefinitionReader.loadBeanDefinitions(configLocations);
}
}
所有这里在最后获取ResourceLoader的时候其实就是AbstractBeanDefinitionReader
具有的属性,之前放进去的AbstractXmlApplicationContext
,也就是最终面向用户的ClassPathXmlApplicationContext
,其本质其实还是DefaultResourceLoader
invokeBeanFactoryPostProcessors(beanFactory)
创建加载完beanFactory和BeanDefinition信息后,接着调用invokeBeanFactoryPostProcessors,invoke的意思是借助。这一步是在bean实例化之前执行BeanFactoryPostProcessor。
/**
* 在bean实例化之前,执行BeanFactoryPostProcessor
*
* @param beanFactory
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
可以看到方法内部就是通过getbeansOfType()
方法先获取BeanFactoryPostProcessor,然后和我们前面章节一样的调用postProcessBeanFactory
。其实后面的BeanPostProcessor
也是一样的操作,所以我们重点看getbeansOfType()
方法是如何自动识别这两个扩展类的。
这里可以debug进去,来到方法的具体实现,可以看到方法内部根据我们传入的参数type的Class类型以及已经存在beanFactory中的beanDefinition信息去匹配判断。
这里说下isAssignabkeFrom()方法,用来判断一个类Class1是否与另一个类Class2相同,或者Class1是否是Class2的超类或接口;他的格式是Class1.isAssignableFrom(Class2);
Class1是父,Class2是子,父-子。同时,我们常用的还有一个instanceof关键字,instanceof 用来判断一个对象实例obj是否是另一个类或接口的实例,格式是obj instanceof ClassName
第一个参数是实例对象,第二个参数是类名;
接着说回代码,isAssignableFrom()方法找到BeanDefinition中的所有的BeanFactoryPostProcessor,调用getBean
,获取到真正的Bean,然后调用postProcessBeanFactory方法,在实例化其他bean之前,修改beanDefinition的信息。
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
Map<String, T> result = new HashMap<>();
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
Class beanClass = beanDefinition.getBeanClass();
if (type.isAssignableFrom(beanClass)) {
T bean = (T) getBean(beanName);
result.put(beanName, bean);
}
});
return result;
}
registerBeanPostProcessors(beanFactory)
执行完BeanFactoryPostProcessor后,接着就是注册BeanPostProcessor,这一步要在其他bean实例化之前注册,这样在其他bean调用getBean方法实例化bean之后,才能执行对应的前置处理和后置处理。
还是getBeansOfType()方法,不同的是,传递的参数变成了BeanPostProcessor.class。这里不再赘述。
/**
* 注册BeanPostProcessor
*
* @param beanFactory
*/
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
}
beanFactory.preInstantiateSingletons()
最后一步是对剩下的bean进行获取。因为BeanFactoryPostProcessor和BeanPostProcessor已经注册,在获取的时候不会重复获取,后续的内容就与上一节的一致了。
@Override
public void preInstantiateSingletons() throws BeansException {
beanDefinitionMap.keySet().forEach(this::getBean);
}
@Override
public Object getBean(String name) throws BeansException {
Object bean = getSingleton(name);
if (bean != null) {
return bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return createBean(name, beanDefinition);
}
从bean的角度看,目前的生命周期如下:
总结:
这一节我们完成了ApplicationContext,Spring中面向使用者的IOC容器,他除了具有BeanFactory的所有功能,同时具有更多面向应用层面的功能。通过这几节的学习,我们知道了BeanFactory和ApplicationContext都支持BeanFactoryPostProcessor和BeanPostProcessor,但是BeanFactory需要我们手动注册,而ApplicationContext是自动注册。
《精通Spring4.x 企业应用开发实战》中的解释。
转载自:https://juejin.cn/post/7212616585767567419