《Spring源码深度解析》六

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

第六章:容器的功能扩展

本章讲解ApplicationContext,一般为企业级应用所使用的容器入口点
本章使用的实现类:
org.springframework.context.support.ClassPathXmlApplicationContext

《Spring源码深度解析》六

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[] {configLocation}, truenull);
}

public ClassPathXmlApplicationContext(
        String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

        throws BeansException 
{
    super(parent);
    //6.1 设置配置路径
    //技巧:可以传多个路径进去,内部会转换为数组,这也是开发中可以用多个xml文件来区分mybatis、springmvc等的原因
    setConfigLocations(configLocations);
    if (refresh) {
        //6.2解析并进行相关的功能实现
        refresh();
    }
}

6.1:设置配置路径

public void setConfigLocations(@Nullable String... locations) {
    if (locations != null) {
        Assert.noNullElements(locations, "Config locations must not be null");
        this.configLocations = new String[locations.length];
        for (int i = 0; i < locations.length; i++) {
            //解析给定路径
            this.configLocations[i] = resolvePath(locations[i]).trim();
        }
    }
    else {
        this.configLocations = null;
    }
}

6.2:扩展功能:解析及功能实现

//几乎包含ApplicationContext所有功能
public void refresh() throws BeansException, IllegalStateException{

6.2.1. 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。
在某种情况下项目的使用需要读取某些系统变量, 而这个变量的设置很可能会影响着系统的正确性
那么ClassPathXm!ApplicationContext为我们提供的这个准备函数就显得非常必要
它可以在Spring启动的时候提前对必需的变量进行存在性验证。
    //prepareRefresh();
6.2.2. 初始化BeanFactory,并进行XML文件读取。
复用BeanFactory中的配置文件读取解析及其他功能,这一步之后,ClassPathXmlApplicationContext实际上就已经包含了B eanFactory 所提供的功能,也就是可以进行bean的提取等基础操作了。
    //ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
6.2.3. 对BeanFactory进行各种功能填充。
@Qualifier与@Autowired这两个注解正是在这一步骤中增加的支持。
    //prepareBeanFactory(beanFactory);
6.2.4. 子类覆盖方法做额外的处理。
空的函数实现postProcessBeanFactory来方便程序员在业务上做进一步扩展。
    //postProcessBeanFactory(beanFactory);
6.2.5. 激活各种BeanFactory处理器。
    //invokeBeanFactoryPostProcessors(beanFactory);
6.2.6. 注册拦截bean创建的bean处理器,这里只是注册,真正的调用是在getBean时候。
    //registerBeanPostProcessors(beanFactory);
6.2.7. 为上下文初始化Message源,即对不同语言的消息体进行国际化处理
    //initMessageSource();
6.2.8. 初始化应用消息广播器,并放入“app licationEventMulticaster” bean 中。
    //initApplicationEventMulticaster();
6.2.9. 留给子类来初始化其他的bean 。
    //onRefresh();
6.2.10. 在所有注册的bean中查找listenerbean,注册到消息广播器中。
    //registerListeners();
6.2.ll. 初始化剩下的单实例(非惰性的)。
    //finishBeanFactoryInitialization(beanFactory);
6.2.12. 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent
通知别人。
    //finishRefresh();
}

6.2.1:环境准备

protected void prepareRefresh() {
    ...
    //1.功能扩展:可留给子类覆盖,扩展Spring,进行个性化的属性处理及设置
    initPropertySources();
    //验证需要的属性文件是否都已经放入环境中,即判断相应属性是否为null
    getEnvironment().validateRequiredProperties();
    ...
}

注释1:如以下需求

《Spring源码深度解析》六《Spring源码深度解析》六

6.2.2:加载BeanFactory

经过此函数后,ApplicationContext就已经拥有了BeanFactory的全部功能

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中
    refreshBeanFactory();
    //返回当前实体的beanFactory属性
    return getBeanFactory();
}

@Override
protected final void refreshBeanFactory() throws BeansException {
    ...
    try {
        //1.创建DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        //2.序列化指定id。如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
        beanFactory.setSerializationId(getId());
        //3.定制BeanFactory。设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖,以及设置@Autowired和@Qualifier注解解析器QualifierAnnotationAutowire-CandidateResolver
        //功能扩展:允许覆盖和允许依赖由使用者通过重写此方法来实现
        customizeBeanFactory(beanFactory);
        //4.(加载BeanDefinition)初始化DocumentReader,并进行XML文件读取及解析,即初始化XmlBeanDefinitionReader
        loadBeanDefinitions(beanFactory);
        //5.使用全局变量记录BeanFactory类实例,即DefaultListableBeanFactory
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    ...
}

6.2.3:对BeanFactory进行各种功能填充

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory){
    //增加对SpEL语言的支持。
    setBeanExpressionResolver
    //增加对属性编辑器的支持。功能扩展:如Date类型不支持,则需要自定义属性编辑器,继承PropertyEditorSupport来实现;
    //流程:在bean的初始化后会调用ResourceEditorRegistrarr的registerCustomEditors(最终调用initBeanWrapper,可参考下文的BeanWrapper)方法进行批量的通用属性编辑器注册。注册后,在属性填充的环节便可以直接让Spring使用这些编辑器进行属性的解析
    addPropertyEditorRegistrar
    //添加BeanPostProcessor
    //在bean 实例化的时候,也就是Spring激活bean的init-method的前后,会调用BeanPostProcessor的postProcessBeforelnitialization方法(取得一些对应的资源)和postProcessAfterlnitialization方法
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    //增加对一些内置类,比如EnvironmentAware 、MessageSourceAware的信息注入。

    //设置了依赖功能可忽略的接口。因为XXXAware类已经不是普通的bean了
    ignoreDependencyInterface()
    //注册一些固定依赖的属性。
    registerResolvableDependency()
    //增加AspectJ的支持。

    //将相关环境变量及属性注册以单例模式注册。
    registerSingleton()
}

BeanWrapper:封装bean。BeanDefinition转换为BeanWrapper后,initBeanWrapper用于对属性的填充,其默认实现为BeanWrapperImpl,此实现类继承了PropertyEditorRegisterSupport,此类的createDefaultEditors中创建了一系列常用的属性编辑器

6.2.4:BeanFactory的后处理

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
    为空
}

注:通过实现Orderer接口,可以控制BeanFactoryPostProcessor的执行次序

1.BeanFactoryPostProcessor作用域:容器级

2.BeanFactoryPostProcessor的典型应用:PropertyPlaceholderConfigurer

通过实现此接口,BeanFactory会在实例化任何bean之前获得配置信息,从而能够正确解析bean描述文件中的变量引用。
场景:

《Spring源码深度解析》六

也可以使用自定义BeanFactoryPostProcessor来去除不要的属性

6.2.5:激活BeanFactoryPostProcessor

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    ...
    }
}

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors){
。。。。
}

对BeanFactoryPostProcessor的处理分为两种情况:

1.对于BeanDefinitionRegistry类的特殊处理
使用三个List来记录三种后处理器(registryPostProcessors、regularPostProcessors、registryPostProcessorBeans),支持排序

2.对于普通的BeanFactoryPostProcessor进行处理
可以忽略BeanDefinitionRegistryPostProcessor

相同点是都需要考虑硬编码注入注册的后处理器以及通过配置注入的后处理器

6.2.6:注册BeanPostProcessor

场景:ApplicationContext实现自动注册以及更多的功能扩展

《Spring源码深度解析》六


protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory){
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    //将配置文件的BeanPostProccessor提取出来并注册进入beanFactory即可
    //BeanProcessor和BeanFactoryPostProcessor区别:
    //BeanFactoryPostProcessor要区分硬编码方式和配置文件方式,而BeanProcessor只有配置文件方式
    //因为硬编码方式是为了提取后处理器并调用,BeanProcessor不需要
}

6.2.7:初始化消息资源、国际化

protected void initMessageSource() {}

6.2.8:初始化ApplicationEventMulticaster

protected void initApplicationEventMulticaster() {}

涉及事件监听,为观察者模式:

SimpleApplicationEventMulticaster为主题类,其multicastEvent方法遍历所有的监听器,调用监听器的onApplicationEvent进行处理;
自己写监听器需要实现ApplicationListener接口和其方法onApplicationEvent,事件类需要继承ApplicationEvent;使用者可以在监听器的onApplicationEvent方法里创建事件类实例,调用想要调用的方法;
最后将事件类实例添加到AbstractApplicationContext实例中,监听器实例添加在配置文件中作为bean,注册到AbstractApplicationContext即可。

6.2.9:留给子类来初始化其他的bean

protected void onRefresh() throws BeansException {
    //为空
}

6.2.10:注册监听器

protected void registerListeners() {
    //分为硬编码方式和配置文件注册两种方式,用set来存储
}

6.2.11:初始化非延迟加载单例、实例化bean对象

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));

        //冻结所有的bean定义,说明注册的bean定义将不被修改或做任何进一步的处理
        beanFactory.freezeConfiguration();
        //初始化非延迟加载。ApplicationContext实现的默认行为是在启动时将所有单例bean提前进行实例化。preInstantiateSingletons的任务就是如此
        beanFactory.preInstantiateSingletons();
    }
}

ConversionService:可以实现Converter接口来实现从String转换Date(或之前所说的使用自定义类型转换器)

底层:Spring采用代理方式(如有aop注解的bean),根据不同的scope来实现bean的实例化

6.2.12:finishRefresh

protected void finishRefresh() {
    //Clear context-level resource caches (such as ASM metadata from scanning).
    clearResourceCaches();
    //初始化lifecycleProcessor
    initLifecycleProcessor();
    //Propagate(传播) refresh to lifecycle processor first.
    //onRefresh():启动所有实现了Lifecycle接口的bean
    getLifecycleProcessor().onRefresh();
    //Publish the final event.
    publishEvent(new ContextRefreshedEvent(this));
    //Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

场景:

《Spring源码深度解析》六

注:Lifecycle,在Tomcat中也有运用,提供统一的开始/关闭机制;还可以通过此接口来进行各种强制转换;也可以定义多个事件来触发,达到可扩展性


原文始发于微信公众号(不止于Java):《Spring源码深度解析》六