6. 实现应用上下文

工程结构

lqf-spring-step-06
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── BeanFactory.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   └── support
│   │           │       ├── AbstractApplicationContext.java
│   │           │       ├── AbstractRefreshableApplicationContext.java
│   │           │       ├── AbstractXmlApplicationContext.java
│   │           │       └── ClassPathXmlApplicationContext.java
│   │           ├── core
│   │           │   └── io
│   │           │       ├── ClassPathResource.java
│   │           │       ├── DefaultResourceLoader.java
│   │           │       ├── FileSystemResource.java
│   │           │       ├── Resource.java
│   │           │       ├── ResourceLoader.java
│   │           │       └── UrlResource.java
│   │           └── util
│   │               └── ClassUtils.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           ├── UserDao.java
    │           ├── UserService.java
    │           └── common
    │               ├── MyBeanFactoryPostProcessor.java
    │               └── MyBeanPostProcessor.java
    └── resources
        ├── important.properties
        ├── spring.xml
        └── springPostProcessor.xml

Spring 应用上下文和对Bean对象扩展机制的类关系,如图:

  • 在整个类图中主要体现出来的是关于 Spring 应用上下文以及对 Bean 对象扩展机制的实现。
  • 以继承了 ListableBeanFactory 接口的 ApplicationContext
    接口开始,扩展出一系列应用上下文的抽象实现类,并最终完成 ClassPathXmlApplicationContext 类的实现。而这个类就是最后交给用户使用的类。
  • 同时在实现应用上下文的过程中,通过定义接口:BeanFactoryPostProcessorBeanPostProcessor 两个接口,把关于对 Bean
    的扩展机制串联进去了。

设计

为了能满足于在 Bean 对象从注册到实例化的过程中执行用户的自定义操作,就需要在 Bean
的定义和初始化过程中插入接口类,这个接口再有外部去实现自己需要的服务。那么在结合对 Spring
框架上下文的处理能力,就可以满足我们的目标需求了。整体设计结构如下图:

  • 满足于对 Bean 对象扩展的两个接口,其实也是 Spring 框架中非常具有重量级的两个接口:BeanFactoryPostProcessor
    BeanPostProcessor,也几乎是在使用 Spring 框架额外新增开发自己组建需求的两个必备接口。
  • BeanFactoryPostProcessor,是由 Spring 框架组建提供的容器扩展机制,允许在 Bean 对象注册后但未实例化之前,对 Bean 的定义信息
    BeanDefinition 执行修改操作。
  • BeanPostProcessor,也是 Spring 提供的扩展机制,不过 BeanPostProcessor 是在 Bean 对象实例化之后修改 Bean 对象,也可以替换
    Bean 对象。这部分与后面要实现的 AOP 有着密切的关系。
  • 同时如果只是添加这两个接口,不做任何包装,那么对于使用者来说还是非常麻烦的。我们希望于开发 Spring 的上下文操作类,把相应的
    XML 加载 、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用。

实现

定义 BeanFactoryPostProcessor

源码: lqf.springframework.beans.factory.config.BeanFactoryPostProcessor

  • 在 Spring
    源码中有这样一段描述 Allows for custom modification of an application context's bean definitions,adapting the bean property values of the context's underlying bean factory.
    其实也就是说这个接口是满足于在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制。

定义 BeanPostProcessor

源码: lqf.springframework.beans.factory.config.BeanPostProcessor

  • 在 Spring
    源码中有这样一段描述 Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
    其实也就是说这个接口是满足于在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之后,提供修改 Bean 对象的机制。
  • 另外此接口提供了两个方法:postProcessBeforeInitialization 用于在 Bean
    对象执行初始化方法之前,执行此方法、postProcessAfterInitialization 用于在 Bean 对象执行初始化方法之后,执行此方法。

定义应用上下文接口

源码1: lqf.springframework.context.ApplicationContext

  • context 是本次实现应用上下文功能新增的服务包
  • ApplicationContext,继承于 ListableBeanFactory,也就继承了关于 BeanFactory 方法,比如一些 getBean 的方法。另外
    ApplicationContext 本身是 Central 接口,但目前还不需要添加一些获取ID和父类上下文,所以暂时没有接口方法的定义。

源码2: lqf.springframework.context.ConfigurableApplicationContext

  • ConfigurableApplicationContext 继承自 ApplicationContext,并提供了 refresh 这个核心方法。如果你有看过一些 Spring
    源码,那么一定会看到这个方法。 接下来也是需要在上下文的实现中完成刷新容器的操作过程。

定义应用上下文抽象类实现

源码: lqf.springframework.context.support.AbstractApplicationContext

  • AbstractApplicationContext 继承 DefaultResourceLoader 是为了处理 spring.xml 配置资源的加载。
  • 之后是在 refresh() 定义实现过程,包括:
    1. 创建 BeanFactory,并加载 BeanDefinition
    2. 获取 BeanFactory
    3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
    4. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
    5. 提前实例化单例Bean对象
  • 另外把定义出来的抽象方法,refreshBeanFactory()、getBeanFactory() 由后面的继承此抽象类的其他抽象类实现。

获取Bean工厂和加载资源

源码: lqf.springframework.context.support.AbstractRefreshableApplicationContext

  • 在 refreshBeanFactory() 中主要是获取了 DefaultListableBeanFactory
    的实例化以及对资源配置的加载操作 loadBeanDefinitions(beanFactory),在加载完成后即可完成对 spring.xml 配置文件中 Bean
    对象的定义和注册,同时也包括实现了接口 BeanFactoryPostProcessor、BeanPostProcessor 的配置 Bean 信息。
  • 但此时资源加载还只是定义了一个抽象类方法 loadBeanDefinitions(DefaultListableBeanFactory beanFactory),继续由其他抽象类继承实现

上下文中对配置信息的加载

源码: lqf.springframework.context.support.AbstractXmlApplicationContext

  • 在 AbstractXmlApplicationContext 抽象类的 loadBeanDefinitions 方法实现中,使用 XmlBeanDefinitionReader 类,处理了关于
    XML 文件配置信息的操作。
  • 同时这里又留下了一个抽象类方法,getConfigLocations(),此方法是为了从入口上下文类,拿到配置信息的地址描述。

应用上下文实现类(ClassPathXmlApplicationContext)

源码: lqf.springframework.context.support.ClassPathXmlApplicationContext

  • 在 ClassPathXmlApplicationContext 类中,主要是实现了 getConfigLocations() 方法,获取配置文件的地址描述信息。
  • 在继承了 AbstractXmlApplicationContext 以及层层抽象类的功能分离实现后,在此类 ClassPathXmlApplicationContext
    的实现中就简单多了,主要是对继承抽象类中方法的调用和提供了配置文件地址信息。

在Bean创建时完成前置和后置处理

源码: lqf.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

  • 实现 BeanPostProcessor 接口后,会涉及到两个接口方法,postProcessBeforeInitializationpostProcessAfterInitialization
    ,分别作用于 Bean 对象执行初始化前后的额外处理。
  • 也就是需要在创建 Bean 对象时,在 createBean 方法中添加 initializeBean(beanName, bean, beanDefinition);
    操作。而这个操作主要主要是对于方法 applyBeanPostProcessorsBeforeInitializationapplyBeanPostProcessorsAfterInitialization
    的使用。
  • 另外需要提一下,applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization
    两个方法是在接口类 AutowireCapableBeanFactory 中新增加的。

总结

  • 本文主要新增了 Spring 框架中两个非常重要的接口 BeanFactoryPostProcess、BeanPostProcessor
    同时还添加了关于应用上下文的实现,ApplicationContext 接口的定义是继承 BeanFactory
    外新增加功能的接口,它可以满足于自动识别、资源加载、容器事件、监听器等功能,同时例如一些国际化支持、单例Bean自动初始化等,也是可以在这个类里实现和扩充的。
  • 通过本文的实现一定会非常了解 BeanFactoryPostProcess、BeanPostProcessor,以后再做一些关于 Spring 中间件的开发时,如果需要用到Bean 对象的获取以及修改一些属性信息,那么就可以使用这两个接口了。同时 BeanPostProcessor 也是实现 AOP 切面技术的关键所在。

返回目录