Spring 扩展及初始化过程分析

Spring 相关

以下分析基于Spring-4.3.10版本

命名空间扩展

Spring中命名空间的扩展(Schema扩展)使用了JAVA SPI机制,具体实现方式为:

  1. 在自己jar包的META-INF目录下添加spring.handlers文件

  2. 文件内容如下:

    http://lj.test.spring.org/schema/test=org.lj.test.spring.schema.TestNamespaceHandler
  3. 编写命名空间解析类org.lj.test.spring.schema.TestNamespaceHandler,此类建议继承自NamespaceHandlerSupport类。用于注册标签名和对应的解析器。

    public class TestNamespaceHandler extends NamespaceHandlerSupport {
       public void init() {
           registerBeanDefinitionParser("test", new TestBeanDefinitionParser(TestConfig.class, true));
       }
    }
  4. 编写TestBeanDefinitionParser类,此类用于将xml解析为一个BeanDefinition,此类为Spring中Bean定义类,用于在编码时返回实际的Bean。

  5. 在spring配置文件中声明命名空间,并使用注解:

    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:test="http://lj.test.spring.org/schema/test"
          xmlns="http://www.springframework.org/schema/beans"
          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
          http://lj.test.spring.org/schema/test http://lj.test.spring.org/schema/test/test.xsd">
    <test:test name="demo-test"/>
    </beans>

Context初始化

以下以ClassPathXmlApplicationContext为例,概述ApplicationContext实例化、初始化过程,其他Context类似。

  1. 设置父容器
  2. 设置配置文件路径。(AbstractApplicationContext.refresh())
  3. 记录启动时间并设置Context状态为active,设置初始化属性并验证通过ConfigurablePropertyResolver#setRequiredProperties设置的、必须的环境变量,实例化广播器初始事件列表集合。(AbstractApplicationContext.prepareRefresh())
  4. 获取、刷新Context内部的BeanFactory。(AbstractApplicationContext.obtainFreshBeanFactory())
    • 销毁可能存在的原有BeanFactory
    • 创建新的BeanFactory,默认为DefaultListableBeanFactory类实例,并设置其父BeanFactory、序列化ID
    • 配置BeanFactory的定制属性,比如是否允许同名Bean、Bean循环依赖、是否忽略lazy-init加载(allowEagerClassLoading)、是否在循环依赖时注入(allowRawInjectionDespiteWrapping)等
    • 从配置文件中加载BeanDefinition,不同的Context实现不同,此处会调用命名空间扩展时,注册的BeanDefinitionParser接口实现类加载BeanDefinition
  5. 设置BeanFactory的公用属性。AbstractApplicationContext.prepareBeanFactory(ConfigurableListableBeanFactory)
    • 设置创建Bean时的类加载器、表达式解析器、Bean属性编辑器
    • 添加Bean创建后处理器ApplicationContextAwareProcessor(BeanPostProcessor,AOP就是通过这个接口的实现类AspectJAwareAdvisorAutoProxyCreator实现的)
    • 添加自动注入时忽略的接口
    • 注册值固定的自动注入类型和对应的值,就是说在自动注入过程中相应的类型注入的是固定不变的
    • 根据BeanFactory内的BeanDefinition,注册特殊的Bean(loadTimeWeaver、environment、systemProperties、systemEnvironment)
  6. 执行BeanFactory后处理逻辑,供子类添加特有的逻辑。AbstractApplicationContext.postProcessBeanFactory(ConfigurableListableBeanFactory)
  7. 调用Context中BeanFactory的后处理器(BeanFactoryPostProcessor接口实现类),后处理器可以来源于BeanFactory中的BeanDefinition。AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)
  8. 注册BeanFactory中BeanDefinition包含的Bean后处理器(BeanPostProcessor),AOP的Bean后处理器就是在这里注册的。AbstractApplicationContext.registerBeanPostProcessors(ConfigurableListableBeanFactory)
  9. 初始化资源串数据源,用于在Context中获取国际化资源串。默认从BeanDefinition中获取ID为messageSource的Bean,获取不到则使用默认的DelegatingMessageSource类实例。AbstractApplicationContext.initMessageSource()
  10. 初始化上下文中的应用事件广播器(ApplicationEventMulticaster),用于广播上下文事件。优先使用BeanDefinition中ID为applicationEventMulticaster的Bean,获取不到则使用SimpleApplicationEventMulticaster。AbstractApplicationContext.initApplicationEventMulticaster()
  11. 调用Context的onrefresh模板方法。AbstractApplicationContext.onRefresh()
  12. 向应用事件广播器注册应用监听器(来源于直接注册或ApplicationListener类型的Bean),并触发广播器初始事件列表集合中的事件。AbstractApplicationContext.registerListeners()
  13. 完成BeanFactory初始化,并初始化单例的、非懒加载的Bean。finishBeanFactoryInitialization(ConfigurableListableBeanFactory)
    • 如果bean是工厂Bean(FactoryBean接口的实现类),则在beanName之前添加&进行标识,供后续实例化使用。
    • 如果单例类实现自SmartInitializingSingleton接口,则调用其afterSingletonsInstantiated方法。
  14. 最后完成Context的初始化。AbstractApplicationContext.finishRefresh()
    • 初始化生命周期处理器,优先使用BeanDefinition中ID为lifecycleProcessor的Bean,获取不到则使用DefaultLifecycleProcessor。
    • 触发生命周期处理器的onRefresh事件(ContextRefreshedEvent,dubbo是通过监听此事件)
    • 通过事件广播器触发ContextRefreshedEvent事件
    • 向JMX中注册本Context

总结

  • Context实例化明显的使用了模板(方法)模式来实现初始化。
  • Context本质上就是对BeanFactory的包装,添加了事件机制、国际化资源串等特性的支持。
  • Context会自动将某些特殊类型的BeanDefinition注册到BeanFactory,例如BeanPostProcessor类型或其他特殊名称的Bean。
  • Context会根据自身的使用场景对BeanFactory进行定制,包括忽略注入接口、设置固定注入对象等。
  • 框架、应用本身可以通过简单的代码支持JMX,提高可维护性。
  • Context生命周期事件继承自ApplicationEvent类。

Bean初始化

以下只记录大概和关键的流程以及相关的方法名。初始方法入口在AbstractBeanFactory.doGetBean。

  1. 根据beanName获取实际的beanName,主要是处理别名、FactoryBean名称的情况。
  2. 尝试从缓存中获取bean实例。
  3. 如果bean为FactoryBean则调用其getObject返回对象,否则直接返回缓存实例。跳过后边的步骤。
  4. 检查是否循环依赖。
  5. 如果本级未包含bean对应的BeanDefinition,则尝试从父BeanFactory中获取对应的BeanDefinition。
  6. 标记Bean已经被创建。
  7. 根据bean获取其对应的RootBeanDefinition。
  8. 检查bean的依赖并注册、实例化依赖bean。
  9. 如果bean是单例,则通过单例方法调用创建bean逻辑(createBean),且创建前后向concurrenthashmap添加、删除当前bean,避免重复创建。
  10. 如果bean是原型的,则直接调用创建bean逻辑(createBean),且创建前、后向ThreadLocal注册、删除beanName。
  11. 如果是其他Scope,则通过scope的get方法调用创建bean逻辑,且创建前、后向ThreadLocal注册、删除beanName。
  12. 通过类型转化器将实例出的bean转化为参数指定的数据类型。

创建bean逻辑

方法入口为AbstractBeanFactory.createBean(name, RootBeanDefinition, args)。

  1. 获取Bean实际的RootBeanDefinition。
  2. 检查Bean内的重载方法。
  3. 尝试调用BeanPostProcessor子接口InstantiationAwareBeanPostProcessor方法,如果返回null则继续创建bean,否则直接返回处理生成的bean(AOP在此处起作用,且Aware的注入也在此处实现)。AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation()
  4. 直接调用默认构造方法或者带有参数的构造方法进行实例化,生成BeanWrapper实例。
  5. 调用BeanPostProcessor子接口MergedBeanDefinitionPostProcessor进行处理实例化后的bean。AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors()

总结

  • Spring中Context加载Bean整体架构类似于Tomcat的类加载器机制(与双亲委派不同),即优先由本BeanFactory加载,找不到后从父BeanFactory加载Bean

猜你喜欢

转载自blog.csdn.net/woshismyawei/article/details/80016382