8. 定义标记类型Aware接口,实现感知容器对象

工程结构

lqf-spring-step-08
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.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
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   └── support
│   │           │       ├── AbstractApplicationContext.java
│   │           │       ├── AbstractRefreshableApplicationContext.java
│   │           │       ├── AbstractXmlApplicationContext.java
│   │           │       ├── ApplicationContextAwareProcessor.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 感知接口的设计和实现类关系,如图:

  • 以上整个类关系就是关于 Aware 感知的定义和对容器感知的实现。
  • Aware 有四个继承的接口,其他这些接口的继承都是为了继承一个标记,有了标记的存在更方便类的操作和具体判断实现。
  • 另外由于 ApplicationContext 并不是在 AbstractAutowireCapableBeanFactory 中 createBean
    方法下的内容,所以需要像容器中注册 addBeanPostProcessor ,再由 createBean 统一调用
    applyBeanPostProcessorsBeforeInitialization 时进行操作。

设计

如果说希望拿到 Spring 框架中一些提供的资源,那么首先需要考虑以一个什么方式去获取,之后你定义出来的获取方式,在 Spring
框架中该怎么去承接,实现了这两项内容,就可以扩展出你需要的一些属于 Spring 框架本身的能力了。

在关于 Bean 对象实例化阶段我们操作过一些额外定义、属性、初始化和销毁的操作,其实我们如果像获取 Spring 一些如
BeanFactory、ApplicationContext 时,也可以通过此类方式进行实现。那么我们需要定义一个标记性的接口,这个接口不需要有方法,它只起到标记作用就
可以,而具体的功能由继承此接口的其他功能性接口定义具体方法,最终这个接口就可以通过 instanceof 进行判断和调用了。整体设计结构如下图:

  • 定义接口 Aware,在 Spring 框架中它是一种感知标记性接口,具体的子类定义和实现能感知容器中的相关对象。
  • 继承 Aware 的接口包括:BeanFactoryAware、BeanClassLoaderAware、BeanNameAware和ApplicationContextAware,当然在 Spring
    源码中还有一些其他关于注解的,不过目前还用不到。
  • 在具体的接口实现过程中你可以看到,一部分(BeanFactoryAware、BeanClassLoaderAware、BeanNameAware)在 factory 的 support
    文件夹下,另外 ApplicationContextAware 是在 context 的 support 中,这是因为不同的内容获取需要在不同的包下提供。所以,在
    AbstractApplicationContext 的具体实现中会用到向 beanFactory 添加 BeanPostProcessor
    内容的 ApplicationContextAwareProcessor 操作,最后由 AbstractAutowireCapableBeanFactory 创建 createBean 时处理相应的调用操作。

实现

定义标记接口

源码: lqf.springframework.beans.factory.Aware

  • 在 Spring 中有特别多类似这样的标记接口的设计方式,它们的存在就像是一种标签一样,可以方便统一摘取出属于此类接口的实现类,通常会有
    instanceof 一起判断使用。

容器感知类

源码1: lqf.springframework.beans.factory.BeanFactoryAware

  • Interface to be implemented by beans that wish to be aware of their owning {@link BeanFactory}.
  • 实现此接口,既能感知到所属的 BeanFactory

源码2: lqf.springframework.beans.factory.BeanClassLoaderAware

  • Callback that allows a bean to be aware of the bean{@link ClassLoader class loader}; that is, the class loader used by
    the present bean factory to load bean classes.
  • 实现此接口,既能感知到所属的 ClassLoader

源码3: lqf.springframework.beans.factory.BeanNameAware

  • Interface to be implemented by beans that want to be aware of their bean name in a bean factory.
  • 实现此接口,既能感知到所属的 BeanName

源码4: lqf.springframework.context.ApplicationContextAware

  • Interface to be implemented by any object that wishes to be notified of the {@link ApplicationContext} that it runs
    in.
  • 实现此接口,既能感知到所属的 ApplicationContext

包装处理器(ApplicationContextAwareProcessor)

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

  • 由于 ApplicationContext 的获取并不能直接在创建 Bean 时候就可以拿到,所以需要在 refresh 操作时,把 ApplicationContext
    写入到一个包装的 BeanPostProcessor 中去,再由
    AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization 方法调用。

注册 BeanPostProcessor

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

  • 在 refresh() 方法中,需要把 ApplicationContextAwareProcessor 注册到 BeanFactory 中去,这样在 createBean
    方法中,就可以调用 applyBeanPostProcessorsBeforeInitialization 方法,执行 ApplicationContextAwareProcessor 的
    postProcessBeforeInitialization 方法,从而实现对 ApplicationContext 的感知。

感知调用操作

源码1: lqf.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
源码2: lqf.springframework.beans.factory.support.AbstractBeanFactory

  • 首先在 initializeBean 中,通过判断 bean instanceof Aware
    ,调用了三个接口方法,BeanFactoryAware.setBeanFactory(this)BeanClassLoaderAware.setBeanClassLoader(getBeanClassLoader())BeanNameAware.setBeanName(beanName)
    ,这样就能通知到已经实现了此接口的类。
  • 另外还向 BeanPostProcessor 中添加了 ApplicationContextAwareProcessor,此时在这个方法中也会被调用到具体的类实现,得到一个
    ApplicationContext 属性。

总结

  • 目前关于 Spring 框架的实现中,某些功能点已经越来趋向于完整,尤其是 Bean 对象的生命周期,已经有了很多的体现。整体总结如图:

  • 本章节关于 Aware 的感知接口的四个继承接口 BeanNameAware, BeanClassLoaderAware, ApplicationContextAware,
    BeanFactoryAware 的实现,又扩展了 Spring 的功能。

    返回目录