Spring 学习(全)

1. 创建简单的Bean容器

对照子工程 lqf-spring-step-01

工程结构

Spring Bean 容器的整个实现内容非常简单,也仅仅是包括了一个简单的 BeanFactory 和 BeanDefinition,这里的类名称是与 Spring
源码中一致,只不过现在的类实现会相对来说更简化一些,在后续的实现过程中再不断的添加内容。

  • BeanDefinition,用于定义 Bean 实例化信息,现在的实现是以一个 Object 存放对象。
  • BeanFactory,代表了 Bean 对象的工厂,可以存放 Bean 定义到 Map 中以及获取。

设计

凡事可以存放数据的具体数据结构实现,都可以称之为容器。例如:ArrayList、LinkedList、HashSet等,在SpringBean容器的场景下,需要一种可以存放和名称索引式的数据结构,所以选择HashMap式最合适的。

HashMap是一种给予扰动函数、负载因子、红黑树转换等技术内容,形成的拉链寻址的数据结构,它能让数据更加散列的分布在哈希桶以及碰撞时形成的链表和红黑树上。
它的数据结构会尽可能最大限度的让整个数据读取的复杂度在 O(1) ~ O(Logn) ~O(n)之间,当然在极端情况下也会有 O(n)
链表查找数据较多的情况。不过我们经过10万数据的扰动函数再寻址验证测试,数据会均匀的散列在各个哈希桶索引上,所以 HashMap
非常适合用在 Spring Bean 的容器实现上。

另外一个间的的Spring Bean 容器实现,还需要Bean的定义、注册、获取三个基本步骤,简化设计如下:

  • 定义:BeanDefinition,在查阅Spring源码时经常看到的一个类,例如它会包括singleton、prototype、BeanClassName等。目前初步实现会更加简单的处理,只定义一个Object类型用于存放对象。
  • 注册:这个过程就相当于把数据存放到HashMap中,只不过现在HashMap存放的是定义了Bean的对象信息。
  • 获取:最后就是获取对象,Bean的名字就是key,Spring 容器初始化好 Bean 后,就可以直接获取了。

实现

Bean 定义

源码详见: lqf.springframework.BeanDefinition

  • 目前的 Bean 定义中,只有一个 Object 用于存放 Bean 对象。如果感兴趣可以参考 Spring 源码中这个类的信息,名称都是一样的。
  • 在后面陆续的实现中会逐步完善 BeanDefinition 相关属性的填充。

Bean 工厂

源码详见: lqf.springframework.BeanFactory

  • 在 Bean 工厂的实现中,包括了 Bean 的注册,这里注册的是 Bean 的定义信息。同时在这个类中还包括了获取 Bean 的操作。
  • 目前的 BeanFactory 仍然是非常简化的实现,但这种简化的实现内容也是整个 Spring 容器中关于 Bean
    使用的最终体现结果,只不过实现过程只展示出基本的核心原理。在后续的补充实现中,这个会不断变得庞大。

总结

  • 关于 Spring Bean 容器的一个雏形就已经实现完成了,相对来说这部分代码并不会难住任何人,只要稍加尝试就可以接受这部分内容的实现。
  • 对于一个知识的学习来说,写代码只是最后的步骤,往往整个思路、设计、方案,才更重要,只要知道了因为什么、所以什么,才能有一个真正的理解。

2. 实现 Bean 的定义、注册、获取

对照子工程 lqf-spring-step-02

工程结构

Spring Bean 容器类关系,如图:

以目前实现结果的类关系图来看,其实已经具备了一定的设计复杂性,这些复杂的类关系设计在各个接口定义和实现以及在抽象类继承中都有所体现,例如:

  • BeanFactory 的定义由 AbstractBeanFactory 抽象类实现接口的 getBean 方法
  • AbstractBeanFactory 又继承了实现了 SingletonBeanRegistry 的DefaultSingletonBeanRegistry 类。这样 AbstractBeanFactory
    抽象类就具备了单例 Bean 的注册功能。
  • AbstractBeanFactory
    中又定义了两个抽象方法:getBeanDefinition(String beanName)createBean(String beanName, BeanDefinition beanDefinition)
    ,而这两个抽象方法分别由 DefaultListableBeanFactoryAbstractAutowireCapableBeanFactory 实现。
  • 最终 DefaultListableBeanFactory 还会继承抽象类 AbstractAutowireCapableBeanFactory 也就可以调用抽象类中的
    createBean 方法了。

综上这一部分的类关系和实现过程还是会有一些复杂的,因为所有的实现都以职责划分、共性分离以及调用关系定义为标准搭建的类关系。这部分内容可能会丰富在复杂业务系统开发中的设计思路。

设计

需要将 Spring Bean 容器完善起来,首先非常重要的一点是在 Bean 注册的时候只注册一个类信息,而不会直接把实例化信息注册到
Spring 容器中。那么就需要修改 BeanDefinition 中的属性 Object 为 Class,接下来在需要做的就是在获取 Bean 对象时需要处理 Bean
对象的实例化操作以及判断当前单例对象在容器中是否已经缓存起来了。整体设计如图:

  • 首先需要定义 BeanFactory 这样一个 Bean 工厂,提供 Bean 的获取方法 getBean(String name),之后这个 Bean 工厂接口由抽象类
    AbstractBeanFactory 实现。这样使用模板模式 (opens new window)
    的设计方式,可以统一收口通用核心方法的调用逻辑和标准定义,也就很好的控制了后续的实现者不用关心调用逻辑,按照统一方式执行。那么类的继承者只需要关心具体方法的逻辑实现即可。
  • 在继承抽象类 AbstractBeanFactory 后的 AbstractAutowireCapableBeanFactory 就可以实现相应的抽象方法了,因为
    AbstractAutowireCapableBeanFactory 本身也是一个抽象类,所以它只会实现属于自己的抽象方法,其他抽象方法由继承
    AbstractAutowireCapableBeanFactory 的类实现。这里就体现了类实现过程中的各司其职,你只需要关心属于你的内容,不是你的内容,不要参与。
  • 单例 SingletonBeanRegistry 的接口定义实现,而 DefaultSingletonBeanRegistry 对接口实现后,会被抽象类 AbstractBeanFactory
    继承。现在 AbstractBeanFactory 就是一个非常完整且强大的抽象类了,也能非常好的体现出它对模板模式的抽象定义。

实现

BeanDefinition 定义

源码详见: lqf.springframework.beans.factory.config.BeanDefinition

  • 在 Bean 定义类中已经把Step01中的 Object bean 替换为 Class,这样就可以把 Bean 的实例化操作放到容器中处理了。Bean
    的实例化操作是放在初始化调用阶段传递给 BeanDefinition 构造函数的。

单例注册接口定义和实现

源码详见: lqf.springframework.beans.factory.config.SingletonBeanRegistry、DefaultSingletonBeanRegistry

  • 这个类比较简单主要是定义了一个获取单例对象的接口。
  • 在 DefaultSingletonBeanRegistry 中主要实现 getSingleton 方法,同时实现了一个受保护的 addSingleton
    方法,这个方法可以被继承此类的其他类调用。包括:AbstractBeanFactory 以及继承的 DefaultListableBeanFactory 调用。

抽象类定义模板方法(AbstractBeanFactory)

源码详见: lqf.springframework.beans.factory.support.AbstractBeanFactory

  • AbstractBeanFactory 首先继承了 DefaultSingletonBeanRegistry,也就具备了使用单例注册类方法。
  • 接下来很重要的一点是关于接口 BeanFactory 的实现,在方法 getBean 的实现过程中可以看到,主要是对单例 Bean
    对象的获取以及在获取不到时需要拿到 Bean 的定义做相应 Bean 实例化操作。那么 getBean
    并没有自身的去实现这些方法,而是只定义了调用过程以及提供了抽象方法,由实现此抽象类的其他类做相应实现。
  • 后续继承抽象类 AbstractBeanFactory
    的类有两个,包括:AbstractAutowireCapableBeanFactory、DefaultListableBeanFactory,这两个类分别做了相应的实现处理。

实例化Bean类(AbstractAutowireCapableBeanFactory)

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

  • 在 AbstractAutowireCapableBeanFactory 类中实现了 Bean 的实例化操作 newInstance
  • 在处理完 Bean 对象的实例化后,直接调用 addSingleton 方法存放到单例对象的缓存中去。

核心类实现(DefaultListableBeanFactory)

源码详见: lqf.springframework.beans.factory.support.DefaultListableBeanFactory

  • DefaultListableBeanFactory 在 Spring 源码中也是一个非常核心的类,在我们目前的实现中也是逐步贴近于源码。
  • DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory 类,也就具备了接口 BeanFactory 和
    AbstractBeanFactory 等一连串的功能实现。
  • 除此之外这个类还实现了接口 BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition
    beanDefinition) 方法,当然你还会看到一个 getBeanDefinition 的实现,它是抽象类 AbstractBeanFactory 中定义的抽象方法。

总结

  • 相对于Step01对 Spring Bean 容器的简单概念实现,本次加强了功能的完善。在实现的过程中也可以看到类的关系变得越来越多了。
  • 在 Spring Bean 容器的实现类中要重点关注类之间的职责和关系,几乎所有的程序功能设计都离不开接口、抽象类、实现、继承,而这些不同特性类的使用就可以非常好的隔离开类的功能职责和作用范围。
  • 在学习的过程中会遇到Step01那样非常简单的代码实现,但要做一个有成长的程序员要记住代码实现只是最后的落地结果,而那些设计上的思考才是最有价值的地方。

3. 基于Cglib实现含构造函数的类实例化策略

对照子工程 lqf-spring-step-03

工程结构

Spring Bean 容器类关系,如图:


主要是在现有工程中添加 InstantiationStrategy 实例化策略接口,以及补充相应的 getBean 入参信息,让外部调用时可以传递构造函数的入参并顺利实例化。

设计

技术设计主要考虑两部分,一个是串流程从哪合理的把构造函数的入参信息传递到实例化操作里,另外一个是怎么去实例化含有构造函数的对象。

  • 在 BeanFactory 中添加 Object getBean(String name, Object... args) 接口,这样就可以在获取 Bean 时把构造函数的入参信息传递进去了。
  • 另外一个核心的内容是使用什么方式来创建含有构造函数的 Bean 对象呢?这里有两种方式可以选择,一个是基于 Java
    本身自带的方法 DeclaredConstructor,另外一个是使用 Cglib 来动态创建 Bean 对象。

实现

新增 getBean 接口

源码详见: lqf.springframework.beans.factory.BeanFactory#getBean(String name, Object... args) 及其实现

  • BeanFactory 中重载了一个含有入参信息 args 的 getBean 方法,这样就可以方便的传递入参给构造函数实例化了。

定义实例化策略接口

源码详见: lqf.springframework.beans.factory.support.InstantiationStrategy

  • 在实例化接口 instantiate 方法中添加必要的入参信息,包括:beanDefinition、 beanName、ctor、args。
  • 其中 Constructor 你可能会有一点陌生,它是 java.lang.reflect 包下的 Constructor
    类,里面包含了一些必要的类信息,有这个参数的目的就是为了拿到符合入参信息相对应的构造函数。
  • 而 args 就是一个具体的入参信息了,最终实例化时候会用到。

JDK 实例化

源码详见: lqf.springframework.beans.factory.support.SimpleInstantiationStrategy

  • 首先通过 beanDefinition 获取 Class 信息,这个 Class 信息是在 Bean 定义的时候传递进去的。
  • 接下来判断 ctor 是否为空,如果为空则是无构造函数实例化,否则就是需要有构造函数的实例化。

这里我们重点关注有构造函数的实例化,实例化方式为 clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
把入参信息传递给 newInstance 进行实例化。

Cglib 实例化

源码详见: lqf.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy

  • 其实 Cglib 创建有构造函数的 Bean 也非常方便,在这里我们更加简化的处理了,不过目前的方式并不会影响创建。

创建策略调用

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

  • 首先在 AbstractAutowireCapableBeanFactory
    抽象类中定义了一个创建对象的实例化策略属性类 InstantiationStrategy instantiationStrategy,这里选择了 Cglib 的实现类。
  • 接下来抽取 createBeanInstance 方法,在这个方法中需要注意 Constructor 代表了你有多少个构造函数,通过
    beanClass.getDeclaredConstructors() 方式可以获取到你所有的构造函数,是一个集合。
  • 接下来就需要循环比对出构造函数集合与入参信息 args 的匹配情况,这里我们对比的方式比较简单,只是一个数量对比,而实际
    Spring 源码中还需要比对入参类型,否则相同数量不同入参类型的情况,就会抛异常了。

总结

  • 主要以完善实例化操作,增加 InstantiationStrategy 实例化策略接口,并新增了两个实例化类。
  • 从不断的完善增加需求可以看到的,当代码结构设计的较为合理的时候,就可以非常容易且方便的进行扩展不同属性的类职责,而不会因为需求的增加导致类结构混乱。所以在业务需求实现的过程中,也要尽可能的去考虑一个良好的扩展性以及拆分好类的职责。

4. 注入属性和依赖对象

工程结构

Spring Bean 容器类关系,如图:

  • 新增加3个类,BeanReference(类引用)、PropertyValue(属性值)、PropertyValues(属性集合),分别用于类和其他类型属性填充操作。
  • 另外改动的类主要是 AbstractAutowireCapableBeanFactory,在 createBean 中补全属性填充部分。

设计

鉴于属性填充是在 Bean 使用 newInstance 或者 Cglib
创建后,开始补全属性信息,那么就可以在类 AbstractAutowireCapableBeanFactory 的 createBean 方法中添加补全属性方法。

  • 属性填充要在类实例化创建之后,也就是需要在 AbstractAutowireCapableBeanFactory 的 createBean
    方法中添加 applyPropertyValues 操作。
  • 由于我们需要在创建Bean时候填充属性操作,那么就需要在 bean 定义 BeanDefinition 类中,添加 PropertyValues 信息。
  • 另外是填充属性信息还包括了 Bean 的对象类型,也就是需要再定义一个 BeanReference,里面其实就是一个简单的 Bean
    名称,在具体的实例化操作时进行递归创建和填充,与 Spring 源码实现一样。

实现

定义属性

源码详见: lqf.springframework.beans.PropertyValue、PropertyValue

  • 这两个类的作用就是创建出一个用于传递类中属性信息的类,因为属性可能会有很多,所以还需要定义一个集合包装下。

Bean定义补全

源码详见: lqf.springframework.beans.factory.config.BeanDefinition

  • 在 Bean 注册的过程中是需要传递 Bean 的信息,在之前的测试中都有所体现 new BeanDefinition(UserService.class,
    propertyValues);
  • 所以为了把属性一定交给 Bean 定义,所以这里填充了 PropertyValues 属性,同时把两个构造函数做了一些简单的优化,避免后面 for
    循环时还得判断属性填充是否为空。

Bean 属性填充

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

  • 主要包括三个方法:createBean、createBeanInstance、applyPropertyValues,这里我们主要关注 createBean 的方法中调用的
    applyPropertyValues 方法。
  • 在 applyPropertyValues 中,通过获取 beanDefinition.getPropertyValues() 循环进行属性填充操作,如果遇到的是
    BeanReference,那么就需要递归获取 Bean 实例,调用 getBean 方法。
  • 当把依赖的 Bean 对象创建完成后,会递归回现在属性填充中。此处引入 hutool-all 依赖。

总结

  • 把 AbstractAutowireCapableBeanFactory 类中的创建对象功能又做了扩充,依赖于是否有构造函数的实例化策略完成后,开始补充
    Bean 属性信息。当遇到 Bean 属性为 Bean 对象时,需要递归处理。最后在属性填充时需要用到反射操作,也可以使用一些工具类处理。
  • 每一个章节的功能点我们都在循序渐进的实现,这样可以让新人更好的接受关于 Spring 中的设计思路。
  • 到这一章节关于 Bean 的创建操作就开发完成了,接下来需要整个框架的基础上完成资源属性的加载,需要去动 Xml 配置了,让我们这小框架越来越像
    Spring。

5. 资源加载器解析文件注册对象

工程结构

lqf-spring-step-05
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── BeanFactory.java
│   │           │       ├── config
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanReference.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
│   │           ├── 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
    └── resources
        ├── important.properties
        └── spring.xml

Spring Bean 容器资源加载和使用类关系,如图:

  • 为了能把Bean的定义、注册和初始化交给 Spring.xml 配置化处理,那么就需要实现两块内容:资源加载器、Xml资源处理类,实现过程主要以对接口
    Resource 、 ResourceLoader 的实现,而另外 BeanDefinitionReader 接口则是对资源的具体使用,将配置信息注册到 Spring 容器中去。
  • 在 Resource 的资源加载器的实现中包括了,ClassPath、系统文件、云配置文件,这三部分与 Spring 源码中的设计和实现保持一致,最终在
    DefaultResourceLoader 中做具体的调用。
  • 接口:BeanDefinitionReader、抽象类:AbstractBeanDefinitionReader、实现类:XmlBeanDefinitionReader,这三部分内容主要是合理清晰的处理了资源读取后的注册
    Bean 容器操作。

另外:还做了相应接口的集成和实现的关系,虽然这些接口目前还并没有太大的作用,但随着框架的逐步完善,它们也会发挥作用。如图:

  • BeanFactory,已经存在的 Bean 工厂接口用于获取 Bean 对象,这次新增加了按照类型获取 Bean
    的方法:<T> T getBean(String name, Class<T> requiredType)
  • ListableBeanFactory,是一个扩展 Bean 工厂接口的接口,新增加了 getBeansOfTypegetBeanDefinitionNames() 方法,在 Spring
    源码中还有其他扩展方法。
  • HierarchicalBeanFactory,在 Spring 源码中它提供了可以获取父类 BeanFactory 方法,属于是一种扩展工厂的层次子接口。
  • AutowireCapableBeanFactory,是一个自动化处理Bean工厂配置的接口,目前案例工程中还没有做相应的实现,后续逐步完善。
  • ConfigurableBeanFactory,可获取 BeanPostProcessor、BeanClassLoader等的一个配置化接口。
  • ConfigurableListableBeanFactory,提供分析和修改Bean以及预先实例化的操作接口,不过目前只有一个 getBeanDefinition 方法。

设计

需要在现有的 Spring 框架雏形中添加一个资源解析器,也就是能读取classpath、本地文件和云文件的配置内容。这些配置内容就是像使用
Spring 时配置的 Spring.xml 一样,里面会包括 Bean 对象的描述和属性信息。 在读取配置文件信息后,接下来就是对配置文件中的 Bean
描述信息解析后进行注册操作,把 Bean 对象注册到 Spring 容器中。整体设计结构如下图:

  • 资源加载器属于相对独立的部分,它位于 Spring 框架核心包下的IO实现内容,主要用于处理Class、本地和云环境中的文件信息。
  • 当资源可以加载后,接下来就是解析和注册 Bean 到 Spring 中的操作,这部分实现需要和 DefaultListableBeanFactory
    核心类结合起来,因为你所有的解析后的注册动作,都会把 Bean 定义信息放入到这个类中。
  • 那么在实现的时候就设计好接口的实现层级关系,包括我们需要定义出 Bean 定义的读取接口 BeanDefinitionReader
    以及做好对应的实现类,在实现类中完成对 Bean 对象的解析和注册。

实现

资源加载接口定义和实现

源码1: lqf.springframework.core.io.Resource

  • 在 Spring 框架下创建 core.io 核心包,在这个包中主要用于处理资源加载流。
  • 定义 Resource 接口,提供获取 InputStream 流的方法,接下来再分别实现三种不同的流文件操作:classPath、FileSystem、URL。

源码2: lqf.springframework.core.io.ClassPathResource

  • 在 ClassPathResource 类中,主要是通过 ClassLoader 获取资源文件的流信息,这里的 ClassLoader
    是通过 ClassUtils.getDefaultClassLoader() 获取的。

源码3: lqf.springframework.core.io.FileSystemResource

  • 通过指定文件路径的方式读取文件信息,这部分大家肯定还是非常熟悉的,经常会读取一些txt、excel文件输出到控制台。

源码4: lqf.springframework.core.io.UrlResource

  • 通过 HTTP 的方式读取云服务的文件,我们也可以把配置文件放到 GitHub 或者 Gitee 上。

包资源加载器

按照资源加载的不同方式,资源加载器可以把这些方式集中到统一的类服务下进行处理,外部用户只需要传递资源地址即可,简化使用。
源码1: lqf.springframework.core.io.ResourceLoader

  • 定义获取资源接口,里面传递 location 地址即可。

源码2: lqf.springframework.core.io.DefaultResourceLoader

  • 在获取资源的实现中,主要是把三种不同类型的资源处理方式进行了包装,分为:判断是否为ClassPath、URL以及文件。
  • 虽然 DefaultResourceLoader 类实现的过程简单,但这也是设计模式约定的具体结果,像是这里不会让外部调用放知道过多的细节,而是仅关心具体调用结果即可。

Bean定义读取接口

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

  • 这是一个 Simple interface for bean definition readers. 其实里面无非定义了几个方法,包括:getRegistry()
    、getResourceLoader(),以及三个加载Bean定义的方法。
  • 这里需要注意 getRegistry()、getResourceLoader(),都是用于提供给后面三个方法的工具,加载和注册,这两个方法的实现会包装到抽象类中,以免污染具体的接口实现方法。

Bean定义抽象类实现

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

  • 抽象类把 BeanDefinitionReader 接口的前两个方法全部实现完了,并提供了构造函数,让外部的调用使用方,把Bean定义注入类,传递进来。
  • 这样在接口 BeanDefinitionReader 的具体实现类中,就可以把解析后的 XML 文件中的 Bean 信息,注册到 Spring 容器去了。

解析XML处理Bean注册

源码: lqf.springframework.beans.factory.xml.XmlBeanDefinitionReader
XmlBeanDefinitionReader 类最核心的内容就是对 XML 文件的解析,把本来在代码中的操作放到了通过解析 XML 自动注册的方式。

  • loadBeanDefinitions 方法,处理资源加载,这里新增加了一个内部方法:doLoadBeanDefinitions,它主要负责解析 xml。
  • 在 doLoadBeanDefinitions 方法中,主要是对xml的读取 XmlUtil.readXML(inputStream) 和元素 Element 解析。在解析的过程中通过循环操作,以此获取
    Bean 配置以及配置中的 id、name、class、value、ref 信息。
  • 最终把读取出来的配置信息,创建成 BeanDefinition 以及 PropertyValue,最终把完整的 Bean 定义内容注册到 Bean
    容器:getRegistry().registerBeanDefinition(beanName, beanDefinition)

总结

  • 以配置文件为入口解析和注册 Bean 信息,最终再通过 Bean 工厂获取 Bean 以及做相应的调用操作。
  • 所有的功能实现都会涉及到很多的代码设计思路,要认真去领悟。

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 切面技术的关键所在。

7. 实现Bean对象的初始化和销毁方法

工程结构

lqf-spring-step-07
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── BeanFactory.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
│   │           │   ├── 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对象扩展机制的类关系,如图:

  • 以上整个类图结构描述出来的就是本次新增 Bean 实例化过程中的初始化方法和销毁方法。
  • 因为一共实现了两种方式的初始化和销毁方法,xml配置和定义接口,所以这里既有 InitializingBean、DisposableBean
    也有需要XmlBeanDefinitionReader 加载 spring.xml 配置信息到 BeanDefinition 中。
  • 另外接口 ConfigurableBeanFactory 定义了 destroySingletons 销毁方法,并由 AbstractBeanFactory 继承的父类
    DefaultSingletonBeanRegistry 实现 ConfigurableBeanFactory 接口定义的 destroySingletons 方法。
  • 最后就是关于向虚拟机注册钩子,保证在虚拟机关闭之前,执行销毁操作。
    • Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("close!")));

设计

可能面对像 Spring 这样庞大的框架,对外暴露的接口定义使用或者xml配置,完成的一系列扩展性操作,都让 Spring 框架看上去很神秘。其实对于这样在
Bean 容器初始化过程中额外添加的处理操作,无非就是预先执行了一个定义好的接口方法或者是反射调用类中xml中配置的方法,最终你只要按照接口定义实现,就会有
Spring 容器在处理的过程中进行调用而已。整体设计结构如下图:

  • 在 spring.xml 配置中添加 init-methoddestroy-method 两个注解,在配置文件加载的过程中,把注解配置一并定义到
    BeanDefinition 的属性当中。这样在 initializeBean 初始化操作的工程中,就可以通过反射的方式来调用配置在 Bean
    定义属性当中的方法信息了。另外如果是接口实现的方式,那么直接可以通过 Bean 对象调用对应接口定义的方法即可,((
    InitializingBean) bean).afterPropertiesSet(),两种方式达到的效果是一样的。
  • 在 Bean 对象实例化过程中,需要在初始化前后执行一些额外的操作,那么就需要定义接口:InitializingBeanDisposableBean,并在
    Bean对象实例化前后执行接口方法。

实现

定义初始化和销毁方法的接口

源码1: lqf.springframework.beans.factory.InitializingBean
源码2: lqf.springframework.beans.factory.DisposableBean

  • InitializingBean、DisposableBean,两个接口方法还是比较常用的,在一些需要结合 Spring
    实现的组件中,经常会使用这两个方法来做一些参数的初始化和销毁操作。比如接口暴漏、数据库数据读取、配置文件加载等等。

Bean属性定义新增初始化和销毁

源码1: lqf.springframework.beans.factory.config.BeanDefinition

  • 在 BeanDefinition 新增加了两个属性:initMethodNamedestroyMethodName,这两个属性是为了在 spring.xml 配置的 Bean
    对象中,可以配置init-method="initDataMethod" destroy-method="destroyDataMethod" 操作,最终实现接口的效果是一样的

源码2: lqf.springframework.beans.factory.xml.XmlBeanDefinitionReader

  • Bean属性定义增加初始化和销毁后,还需要在XmlBeanDefinitionReader类中,增加对新增属性的读取,并添加到BeanDefinition中

执行 Bean 对象的初始化方法

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

  • 抽象类 AbstractAutowireCapableBeanFactory 中的 createBean 是用来创建 Bean 对象的方法,在这个方法中之前已经扩展了
    BeanFactoryPostProcessor、BeanPostProcessor 操作,这里我们继续完善执行 Bean 对象的初始化方法的处理动作。
  • 在方法 invokeInitMethods 中,主要分为两块来执行实现了 InitializingBean 接口的操作,处理 afterPropertiesSet
    方法。另外一个是判断配置信息 init-method 是否存在,执行反射调用 initMethod.invoke(bean)。这两种方式都可以在 Bean
    对象初始化过程中进行处理加载 Bean 对象中的初始化操作,让使用者可以额外新增加自己想要的动作。

定义销毁方法适配器(接口和配置)

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

  • 目前有实现接口 DisposableBean配置信息 destroy-method,两种方式。而这两种方式的销毁动作是由
    AbstractApplicationContext
    在注册虚拟机钩子后看,虚拟机关闭前执行的操作动作。
  • 在销毁执行时不太希望还得关注都销毁那些类型的方法,它的使用上更希望是有一个统一的接口进行销毁,所以这里就新增了适配类,做统一处理。

创建Bean时注册销毁方法对象

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

  • 在创建 Bean 对象的实例的时候,需要把销毁方法保存起来,方便后续执行销毁动作进行调用。
  • 那么这个销毁方法的具体方法信息,会被注册到 DefaultSingletonBeanRegistry
    中新增加的 Map<String, DisposableBean> disposableBeans 属性中去,因为这个接口的方法最终可以被类
    AbstractApplicationContext 的 close 方法通过 getBeanFactory().destroySingletons() 调用。
  • 在注册销毁方法的时候,会根据是接口类型和配置类型统一交给 DisposableBeanAdapter 销毁适配器类来做统一处理

虚拟机关闭钩子注册调用销毁方法

源码1: lqf.springframework.context.ConfigurableApplicationContext
源码2: lqf.springframework.context.support.AbstractApplicationContext

  • 在 ConfigurableApplicationContext 接口中定义了一个方法:registerShutdownHook(),这个方法是用于注册虚拟机关闭钩子的。

总结

  • 主要完成了关于初始和销毁在使用接口定义 implements InitializingBean, DisposableBean
    和在spring.xml中配置 init-method="initDataMethod" destroy-method="destroyDataMethod"
    的两种具体在 AbstractAutowireCapableBeanFactory 完成初始方法和AbstractApplicationContext 处理销毁动作的具体实现过程。
  • 可以看到目前这个 Spring 框架对 Bean 的操作越来越完善了,可扩展性也不断的增强。你既可以在Bean注册完成实例化前进行
    BeanFactoryPostProcessor 操作,也可以在Bean实例化过程中执行前置和后置操作,现在又可以执行Bean的初始化方法和销毁方法。
    所以一个简单的Bean对象,已经被赋予了各种扩展能力。

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 的功能。

9. Bean对象作用域以及FactoryBean的实现和使用

工程结构

lqf-spring-step-09
├── 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
│   │           │       ├── FactoryBean.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
│   │           │       │   ├── FactoryBeanRegistrySupport.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
    │           ├── IUserDao.java
    │           ├── ProxyBeanFactory.java
    │           ├── SpringTest.java
    │           ├── UserDao.java
    │           ├── UserService.java
    │           └── common
    │               ├── MyBeanFactoryPostProcessor.java
    │               └── MyBeanPostProcessor.java
    └── resources
        ├── important.properties
        ├── spring.xml
        └── springPostProcessor.xml

Spring 单例、原型以及 FactoryBean 功能实现类关系,如图:

  • 以上整个类关系就是关于 Bean 对象作用域以及 FactoryBean 的实现。
  • 整个实现的过程并不复杂,只是在现有的 AbstractAutowireCapableBeanFactory 类以及继承的抽象类 AbstractBeanFactory 中进行扩展。
  • 不过这次把 AbstractBeanFactory 继承的 DefaultSingletonBeanRegistry 类,中间加了一层 FactoryBeanRegistrySupport,这个类在
    Spring 框架中主要是处理关于 FactoryBean 注册的支撑操作。

设计

关于提供一个能让使用者定义复杂的 Bean 对象,功能点非常不错,意义也非常大,因为这样做了之后 Spring
的生态种子孵化箱就此提供了,谁家的框架都可以在此标准上完成自己服务的接入。

但这样的功能逻辑设计上并不复杂,因为整个 Spring
框架在开发的过程中就已经提供了各项扩展能力的接茬,你只需要在合适的位置提供一个接茬的处理接口调用和相应的功能逻辑实现即可,像这里的目标实现就是对外提供一个可以二次从
FactoryBean 的 getObject 方法中获取对象的功能即可,这样所有实现此接口的对象类,就可以扩充自己的对象功能了。整体设计结构如下图:

  • 整个的实现过程包括了两部分,一个解决单例还是原型对象,另外一个处理 FactoryBean
    类型对象创建过程中关于获取具体调用对象的 getObject 操作。
  • SCOPE_SINGLETONSCOPE_PROTOTYPE
    对象类型的创建获取方式,主要区分在于AbstractAutowireCapableBeanFactory#createBean创建完成对象后是否放入到内存中,如果不放入则每次获取都会重新创建。
  • createBean 执行对象创建、属性填充、依赖加载、前置后置处理、初始化等操作后,就要开始做执行判断整个对象是否是一个
    FactoryBean
    对象,如果是这样的对象,就需要再继续执行获取 FactoryBean 具体对象中的 getObject 对象了。整个 getBean
    过程中都会新增一个单例类型的判断factory.isSingleton(),用于决定是否使用内存存放对象信息。

实现

Bean的作用范围定义和xml解析

源码1: lqf.springframework.beans.factory.config.BeanDefinition

  • singleton、prototype,是本次在 BeanDefinition 类中新增加的两个属性信息,用于把从 spring.xml 中解析到的 Bean 对象作用范围填充到属性中。

源码2: lqf.springframework.beans.factory.xml.XmlBeanDefinitionReader

  • 在解析 XML 处理类 XmlBeanDefinitionReader 中,新增加了关于 Bean 对象配置中 scope 的解析,并把这个属性信息填充到 Bean
    定义中。beanDefinition.setScope(beanScope)

创建和修改对象时候判断单例和原型模式

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

  • 单例模式和原型模式的区别就在于是否存放到内存中,如果是原型模式那么就不会存放到内存中,每次获取都重新创建对象,另外非
    Singleton 类型的 Bean 不需要执行销毁方法。
  • 所以这里的代码会有两处修改,一处是 createBean 中判断是否添加到 addSingleton(beanName, bean);,另外一处是
    registerDisposableBeanIfNecessary 销毁注册中的判断 if (!beanDefinition.isSingleton()) return;

定义 FactoryBean 接口

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

  • FactoryBean 中需要提供3个方法,获取对象、对象类型,以及是否是单例对象,如果是单例对象依然会被放到内存中。

实现一个 FactoryBean 注册服务

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

  • FactoryBeanRegistrySupport 类主要处理的就是关于 FactoryBean
    此类对象的注册操作,之所以放到这样一个单独的类里,就是希望做到不同领域模块下只负责各自需要完成的功能,避免因为扩展导致类膨胀到难以维护。
  • 同样这里也定义了缓存操作 factoryBeanObjectCache,用于存放单例类型的对象,避免重复创建。
  • doGetObjectFromFactoryBean 是具体的获取 FactoryBean#getObject() 方法,因为既有缓存的处理也有对象的获取,所以额外提供了
    getObjectFromFactoryBean 进行逻辑包装,这部分的操作方式是不和你日常做的业务逻辑开发非常相似。

扩展 AbstractBeanFactory 创建对象逻辑

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

  • 首先这里把 AbstractBeanFactory 原来继承的 DefaultSingletonBeanRegistry,修改为继承 FactoryBeanRegistrySupport。因为需要扩展出创建
    FactoryBean 对象的能力,所以这就想一个链条服务上,截出一个段来处理额外的服务,并把链条再链接上。
  • 此处新增加的功能主要是在 doGetBean 方法中,添加了调用 (T) getObjectForBeanInstance(sharedInstance, name) 对获取
    FactoryBean 的操作。
  • 在 getObjectForBeanInstance 方法中做具体的 instanceof 判断,另外还会从 FactoryBean 的缓存中获取对象,如果不存在则调用
    FactoryBeanRegistrySupport#getObjectFromFactoryBean,执行具体的操作。

总结

  • 在 Spring 框架整个开发的过程中,前期的各个功能接口类扩展的像膨胀了似的,但到后期在完善功能时,就没有那么难了,反而深入理解后会觉得功能的补充,都比较简单。只需要再所遇领域范围内进行扩展相应的服务实现即可。
  • 当仔细阅读完关于 FactoryBean 的实现以及测试过程的使用,以后再需要使用 FactoryBean 开发相应的组件时候,一定会非常清楚它是如何创建自己的复杂
    Bean 对象以及在什么时候初始化和调用的。遇到问题也可以快速的排查、定位和解决。

10.容器事件和事件监听器

工程结构

lqf-spring-step-10
├── 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
│   │           │       ├── FactoryBean.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
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.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
    │           └── event
    │               ├── ContextClosedEventListener.java
    │               ├── ContextRefreshedEventListener.java
    │               ├── CustomEvent.java
    │               └── CustomEventListener.java
    └── resources
        ├── important.properties
        ├── spring.xml
        └── springPostProcessor.xml

容器事件和事件监听器实现类关系,如图:

  • 以上整个类关系图以围绕实现 event 事件定义、发布、监听功能实现和把事件的相关内容使用 AbstractApplicationContext#refresh
    进行注册和处理操作。
  • 在实现的过程中主要以扩展 spring context 包为主,事件的实现也是在这个包下进行扩展的,当然也可以看出来目前所有的实现内容,仍然是以IOC为主。
  • ApplicationContext 容器继承事件发布功能接口 ApplicationEventPublisher,并在实现类中提供事件监听功能。
  • ApplicationEventMulticaster 接口是注册监听器和发布事件的广播器,提供添加、移除和发布事件方法。
  • 最后是发布容器关闭事件,这个仍然需要扩展到 AbstractApplicationContext#close 方法中,由注册到虚拟机的钩子实现。

设计

在 Spring 框架中,事件监听器的设计和实现,是为了让使用者可以在容器初始化、刷新、关闭等过程中,可以自定义一些操作,这样就可以在容器的生命周期
中,做一些自己想要的操作。

在功能实现上我们需要定义出事件类、事件监听、事件发布,而这些类的功能需要结合到 Spring 的
AbstractApplicationContext#refresh(),以便于处理事件初始化和注册事件监听器的操作。
整体设计结构如下图:

  • 在整个功能实现过程中,仍然需要在面向用户的应用上下文 AbstractApplicationContext
    中添加相关事件内容,包括:初始化事件发布者、注册事件监听器、发布容器刷新完成事件。
  • 使用观察者模式定义事件类、监听类、发布类,同时还需要完成一个广播器的功能,接收到事件推送时进行分析处理符合监听事件接受者感兴趣的事件,也就是使用
    isAssignableFrom 进行判断。
  • isAssignableFrom 和 instanceof 相似,不过 isAssignableFrom
    是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)
    结果是true,证明B可以转换成为A,也就是A可以由B转换而来。

实现

定义和实现事件

源码1: lqf.springframework.context.ApplicationEvent

  • 以继承 java.util.EventObject 定义出具备事件功能的抽象类 ApplicationEvent,后续所有事件的类都需要继承这个类。

源码2: lqf.springframework.context.event.ApplicationContextEvent
源码3: lqf.springframework.context.event.ContextClosedEvent
源码4: lqf.springframework.context.event.ContextRefreshedEvent

  • ApplicationEvent 是定义事件的抽象类,所有的事件包括关闭、刷新,以及用户自己实现的事件,都需要继承这个类。
  • ContextClosedEvent、ContextRefreshedEvent,分别是 Spring 框架自己实现的两个事件类,可以用于监听刷新和关闭动作。

事件广播器

源码1: lqf.springframework.context.event.ApplicationEventMulticaster

  • 在事件广播器中定义了添加监听和删除监听的方法以及一个广播事件的方法 multicastEvent 最终推送时间消息也会经过这个接口方法来处理谁该接收事件。

源码2: lqf.springframework.context.event.AbstractApplicationEventMulticaster

  • 在 AbstractApplicationEventMulticaster 中实现了 ApplicationEventMulticaster 接口,提供了一个监听器的注册和移除的操作,以及一个广播事件的操作。
  • 除了像 addApplicationListener、removeApplicationListener,这样的通用方法,这里这个类中主要是对 getApplicationListeners 和
    supportsEvent 的处理。 getApplicationListeners 方法主要是摘取符合广播事件中的监听处理器,具体过滤动作在 supportsEvent
    方法中。
  • 在 supportsEvent 方法中,主要包括对Cglib、Simple不同实例化需要获取目标Class,Cglib代理类需要获取父类的Class,普通实例化的不需要。接下来就是通过提取接口和对应的
    ParameterizedType 和 eventClassName,方便最后确认是否为子类和父类的关系,以此证明此事件归这个符合的类处理。

supportsEvent 方法运行截图

  • 在代码调试中可以看到,最终 eventClassName 和 event.getClass() 在 isAssignableFrom 判断下为 true
  • 关于 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 可以尝试在 AbstractApplicationContext 类中更换验证。

事件发布者的定义和实现

源码1: lqf.springframework.context.ApplicationEventPublisher

  • ApplicationEventPublisher 是整个一个事件的发布接口,所有的事件都需要从这个接口发布出去。

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

  • 在抽象应用上下文 AbstractApplicationContext#refresh
    中,主要新增了 初始化事件发布者注册事件监听器发布容器刷新完成事件,三个方法用于处理事件操作。
  • 初始化事件发布者(initApplicationEventMulticaster),主要用于实例化一个 SimpleApplicationEventMulticaster,这是一个事件广播器。
  • 注册事件监听器(registerListeners),通过 getBeansOfType 方法获取到所有从 spring.xml 中加载到的事件配置 Bean 对象。
    发布容器刷新完成事件(finishRefresh),发布了第一个服务器启动完成后的事件,这个事件通过 publishEvent 发布出去,其实也就是调用了
    applicationEventMulticaster.multicastEvent(event); 方法。
  • 最后是一个 close 方法中,新增加了发布一个容器关闭事件。publishEvent(new ContextClosedEvent(this));

总结

  • 在整个手写 Spring 框架的学习过程中,可以逐步看到很多设计模式的使用,比如:简单工厂BeanFactory、工厂方法FactoryBean、策略模式访问资源,现在又实现了一个观察者模式的具体使用。所以学习
    Spring 的过程中,要更加注意关于设计模式的运用。
  • 关于观察者模式的实现过程,主要包括了事件的定义、事件的监听和发布事件,发布完成后根据匹配策略,监听器就会收到属于自己的事件内容,并做相应的处理动作,这样的观察者模式其实日常我们也经常使用,不过在结合
    Spring 以后,除了设计模式的学习,还可以学到如何把相应观察者的实现和应用上下文结合。

11. 基于JDK、Cglib实现AOP切面

工程结构

lqf-spring-step-11
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   └── AspectJExpressionPointcut.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       └── ReflectiveMethodInvocation.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.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
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.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
    │           ├── event
    │           │   ├── ContextClosedEventListener.java
    │           │   ├── ContextRefreshedEventListener.java
    │           │   ├── CustomEvent.java
    │           │   └── CustomEventListener.java
    │           └── service
    │               ├── IUserService.java
    │               ├── UserService.java
    │               └── UserServiceInterceptor.java
    └── resources
        ├── important.properties
        ├── spring.xml
        └── springPostProcessor.xml

AOP 切点表达式和使用以及基于 JDK 和 CGLIB 的动态代理类关系,如图

  • 整个类关系图就是 AOP 实现核心逻辑的地方,上面部分是关于方法的匹配实现,下面从 AopProxy 开始是关于方法的代理操作。
  • AspectJExpressionPointcut 的核心功能主要依赖于 aspectj 组件并处理 Pointcut、ClassFilter、MethodMatcher
    接口实现,专门用于处理类和方法的匹配过滤操作。
  • AopProxy 是代理的抽象对象,它的实现主要是基于 JDK 的代理和 Cglib 代理。在前面章节关于对象的实例化
    CglibSubclassingInstantiationStrategy,我们也使用过 Cglib 提供的功能。

设计

在把 AOP 整个切面设计融合到 Spring 前,我们需要解决两个问题,包括:如何给符合规则的方法做代理
以及做完代理方法的案例后,把类的职责拆分出来

而这两个功能点的实现,都是以切面的思想进行设计和开发。如果不是很清楚 AOP 是啥,你可以把切面理解为用刀切韭菜,一根一根切总是有点慢,
那么用手(代理)把韭菜捏成一把,用菜刀或者斧头这样不同的拦截操作来处理。而程序中其实也是一样,只不过韭菜变成了方法,菜刀变成了拦截方法。
整体设计结构如下图:

  • 就像在使用 Spring 的 AOP 一样,只处理一些需要被拦截的方法。在拦截方法后,执行你对方法的扩展操作。
  • 那么我们就需要先来实现一个可以代理方法的 Proxy,其实代理方法主要是使用到方法拦截器类处理方法的调用
    MethodInterceptor#invoke,而不是直接使用 invoke 方法中的入参 Method method 进行 method.invoke(targetObj, args)
    这块是整个使用时的差异。
  • 除了以上的核心功能实现,还需要使用到 org.aspectj.weaver.tools.PointcutParser
    处理拦截表达式 execution(* lqf.springframework.service.IUserService.*(..)),有了方法代理和处理拦截,我们就可以完成设计出一个
    AOP 的雏形了。

实现

切点表达式

  • 定义接口
    • 源码1: lqf.springframework.aop.Pointcut
      • 切入点接口,定义用于获取 ClassFilter、MethodMatcher 的两个类,这两个接口获取都是切点表达式提供的内容。
    • 源码2: lqf.springframework.aop.MethodMatcher
      +
      方法匹配,找到表达式范围内匹配下的目标类和方法。在上文的案例中有所体现:methodMatcher.matches(method, targetObj.getClass())
  • 实现切点表达式类
    • 源码: lqf.springframework.aop.aspectj.AspectJExpressionPointcut
      • AspectJExpressionPointcut 类是 AspectJ 表达式的实现类,主要是用于处理切点表达式的解析和匹配操作。
      • 在 AspectJExpressionPointcut 类中,主要是使用到了 AspectJ 提供的 PointcutParser 处理切点表达式,然后再通过
        PointcutExpression#matches 进行匹配操作。

包装切面通知信息

源码: lqf.springframework.aop.AdvisedSupport

  • AdvisedSupport,主要是用于把代理、拦截、匹配的各项属性包装到一个类中,方便在 Proxy 实现类进行使用。
  • TargetSource,是一个目标对象,在目标对象类中提供 Object 入参属性,以及获取目标类 TargetClass 信息。
  • MethodInterceptor,是一个具体拦截方法实现类,由用户自己实现 MethodInterceptor#invoke 方法,做具体的处理。
  • MethodMatcher,是一个匹配方法的操作,这个对象由 AspectJExpressionPointcut 提供服务。

代理抽象实现(JDK&Cglib)

定义接口 源码1: lqf.springframework.aop.framework.AopProxy

  • 定义一个标准接口,用于获取代理类。因为具体实现代理的方式可以有 JDK 方式,也可以是 Cglib 方式,所以定义接口会更加方便管理实现类。

源码2: lqf.springframework.aop.framework.JdkDynamicAopProxy

  • 基于 JDK 实现的代理类,需要实现接口 AopProxy、InvocationHandler,这样就可以把代理对象 getProxy 和反射调用方法 invoke
    分开处理了。
  • getProxy 方法中的是代理一个对象的操作,需要提供入参 ClassLoader、AdvisedSupport、和当前这个类 this,因为这个类提供了
    invoke 方法。
  • invoke 方法中主要处理匹配的方法后,使用用户自己提供的方法拦截实现,做反射调用 methodInterceptor.invoke 。
  • 这里还有一个 ReflectiveMethodInvocation,其他它就是一个入参的包装信息,提供了入参对象:目标对象、方法、入参。

源码3: lqf.springframework.aop.framework.Cglib2AopProxy

  • 基于 Cglib 使用 Enhancer 代理的类可以在运行期间为接口使用底层 ASM 字节码增强技术处理对象的代理对象生成,因此被代理类不需要实现任何接口。
  • 关于扩展进去的用户拦截方法,主要是在 Enhancer#setCallback 中处理,用户自己的新增的拦截处理。这里可以看到
    DynamicAdvisedInterceptor#intercept 匹配方法后做了相应的反射操作。

总结

  • 从本文对 Proxy#newProxyInstance、MethodInterceptor#invoke,的使用验证切面核心原理以及再把功能拆解到 Spring
    框架实现中,可以看到一个貌似复杂的技术其实核心内容往往没有太多,但因为需要为了满足后续更多的扩展就需要进行职责解耦和包装,通过这样设计模式的使用,以此让调用方能更加简化,自身也可以不断按需扩展。
  • AOP 的功能实现目前还没有与 Spring 结合,只是对切面技术的一个具体实现,可以先学习到如何处理代理对象、过滤方法、拦截方法,以及使用
    Cglib 和 JDK 代理的区别,其实这与的技术不只是在 Spring 框架中有所体现,在其他各类需要减少人工硬编码的场景下,都会用到。

12. 把AOP拓展到Bean的生命周期

工程结构

lqf-spring-step-12
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── Advisor.java
│   │           │   ├── BeforeAdvice.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodBeforeAdvice.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── PointcutAdvisor.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   ├── AspectJExpressionPointcut.java
│   │           │   │   └── AspectJExpressionPointcutAdvisor.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       ├── ProxyFactory.java
│   │           │       ├── ReflectiveMethodInvocation.java
│   │           │       ├── adapter
│   │           │       │   └── MethodBeforeAdviceInterceptor.java
│   │           │       └── autoproxy
│   │           │           └── DefaultAdvisorAutoProxyCreator.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   ├── InstantiationAwareBeanPostProcessor.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.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
    │           └── service
    │               ├── IUserService.java
    │               ├── UserService.java
    │               ├── UserServiceBeforeAdvice.java
    │               └── UserServiceInterceptor.java
    └── resources
        ├── important.properties
        ├── spring.xml
        └── springPostProcessor.xml

AOP 动态代理融入到Bean的生命周期中类关系,如图:

  • 整个类关系图中可以看到,在以 BeanPostProcessor 接口实现继承的 InstantiationAwareBeanPostProcessor 接口后,做了一个自动代理创建的类
    DefaultAdvisorAutoProxyCreator,这个类的就是用于处理整个 AOP 代理融入到 Bean 生命周期中的核心类。
  • DefaultAdvisorAutoProxyCreator 会依赖于拦截器、代理工厂和Pointcut与Advisor的包装服务
    AspectJExpressionPointcutAdvisor,由它提供切面、拦截方法和表达式。
  • Spring 的 AOP 把 Advice 细化了 BeforeAdvice、AfterAdvice、AfterReturningAdvice、ThrowsAdvice,目前我们做的测试案例中只用到了
    BeforeAdvice,这部分可以对照 Spring 的源码进行补充测试。

设计

在有了AOP的核心功能实现后,把这部分功能服务融入到 Spring 其实也不难,只不过要解决几个问题,包括:怎么借着 BeanPostProcessor
把动态代理融入到 Bean 的生命周期中,以及如何组装各项切点、拦截、前置的功能和适配对应的代理器。整体设计结构如下图:

  • 为了可以让对象创建过程中,能把xml中配置的代理对象也就是切面的一些类对象实例化,就需要用到 BeanPostProcessor
    提供的方法,因为这个类的中的方法可以分别作用与 Bean 对象执行初始化前后修改 Bean 的对象的扩展信息。但这里需要集合于
    BeanPostProcessor 实现新的接口和实现类,这样才能定向获取对应的类信息。
  • 但因为创建的是代理对象不是之前流程里的普通对象,所以我们需要前置于其他对象的创建,所以在实际开发的过程中,需要在
    AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。
  • 这里还包括要解决方法拦截器的具体功能,提供一些 BeforeAdvice、AfterAdvice
    的实现,让用户可以更简化的使用切面功能。除此之外还包括需要包装切面表达式以及拦截方法的整合,以及提供不同类型的代理方式的代理工厂,来包装切面服务。

实现

定义 Advice 拦截器链

源码1: lqf.springframework.aop.BeforeAdvice
源码2: lqf.springframework.aop.MethodBeforeAdvice

  • 在 Spring 框架中,Advice 都是通过方法拦截器 MethodInterceptor 实现的。环绕 Advice 类似一个拦截器的链路,Before
    Advice、After advice等,不过暂时我们需要那么多就只定义了一个 MethodBeforeAdvice 的接口定义。

定义 Advisor 访问者

源码1: lqf.springframework.aop.Advisor
源码2: lqf.springframework.aop.PointcutAdvisor

  • PointcutAdvisor 承担了 Pointcut 和 Advice 的组合,Pointcut 用于获取 JoinPoint,而 Advice 决定于 JoinPoint 执行什么操作。

源码3: lqf.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor

  • AspectJExpressionPointcutAdvisor 实现了 PointcutAdvisor 接口,把切面 pointcut、拦截方法 advice 和具体的拦截表达式包装在一起。这样就可以在
    xml 的配置中定义一个 pointcutAdvisor 切面拦截器了。

方法拦截器

源码: lqf.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor

  • MethodBeforeAdviceInterceptor 实现了 MethodInterceptor 接口,在 invoke 方法中调用 advice 中的 before 方法,传入对应的参数信息。
  • 而这个 advice.before 则是用于自己实现 MethodBeforeAdvice 接口后做的相应处理。

代理工厂

源码: lqf.springframework.aop.framework.ProxyFactory

  • 代理工厂主要解决的是关于 JDK 和 Cglib 两种代理的选择问题,有了代理工厂就可以按照不同的创建需求进行控制。

融入Bean生命周期的自动代理创建者

源码: lqf.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator

  • DefaultAdvisorAutoProxyCreator 类的主要核心实现在于 postProcessBeforeInstantiation 方法中,从通过
    beanFactory.getBeansOfType 获取 AspectJExpressionPointcutAdvisor 开始。
  • 获取了 advisors 以后就可以遍历相应的 AspectJExpressionPointcutAdvisor 填充对应的属性信息,包括:目标对象、拦截方法、匹配器,之后返回代理对象即可。
  • 现在调用方获取到的这个 Bean 对象就是一个已经被切面注入的对象了,当调用方法的时候,则会被按需拦截,处理用户需要的信息。

融入到Bean的生命周期

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

  • 因为创建的是代理对象不是之前流程里的普通对象,所以我们需要前置于其他对象的创建,即需要在
    AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。

总结

  • 本章节实现 AOP 功能的外在体现主要是把以前自己在单元测试中的切面拦截,交给 Spring 的 xml 配置了,也就不需要自己手动处理了。
  • 一个功能的实现往往包括核心部分、组装部分、链接部分,为了这些各自职责的分工,则需要创建接口和类,由不同关系的继承、实现进行组装。
  • 目前实现的 AOP 与 Spring 源码中的核心逻辑是类似的,但更会偏简单一些,也不会考虑更多的复杂场景遇到的问题,包括是否有构造函数、是否为代理中的切面等。

13. 自动扫描Bean对象注册

工程结构

lqf-spring-step-13
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── Advisor.java
│   │           │   ├── BeforeAdvice.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodBeforeAdvice.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── PointcutAdvisor.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   ├── AspectJExpressionPointcut.java
│   │           │   │   └── AspectJExpressionPointcutAdvisor.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       ├── ProxyFactory.java
│   │           │       ├── ReflectiveMethodInvocation.java
│   │           │       ├── adapter
│   │           │       │   └── MethodBeforeAdviceInterceptor.java
│   │           │       └── autoproxy
│   │           │           └── DefaultAdvisorAutoProxyCreator.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── PropertyPlaceholderConfigurer.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   ├── InstantiationAwareBeanPostProcessor.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── annotation
│   │           │   │   ├── ClassPathBeanDefinitionScanner.java
│   │           │   │   ├── ClassPathScanningCandidateComponentProvider.java
│   │           │   │   └── Scope.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.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
│   │           ├── stereotype
│   │           │   └── Component.java
│   │           └── util
│   │               └── ClassUtils.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           └── service
    │               ├── IUserService.java
    │               └── UserService.java
    └── resources
        ├── spring-property.xml
        ├── spring-scan.xml
        └── token.properties

在Bean的生命周期中自动加载包扫描注册Bean对象和设置占位符属性的类关系,如图:

  • 整个类的关系结构来看,其实涉及的内容并不多,主要包括的就是 xml 解析类 XmlBeanDefinitionReader 对
    ClassPathBeanDefinitionScanner#doScan 的使用。
  • 在 doScan 方法中处理所有指定路径下添加了注解的类,拆解出类的信息:名称、作用范围等,进行创建 BeanDefinition 好用于 Bean
    对象的注册操作。
  • PropertyPlaceholderConfigurer 目前看上去像一块单独的内容,后续会把这块的内容与自动加载 Bean
    对象进行整合,也就是可以在注解上使用占位符配置一些在配置文件里的属性信息。

设计

为了可以简化 Bean 对象的配置,让整个 Bean
对象的注册都是自动扫描的,那么基本需要的元素包括:扫描路径入口、XML解析扫描信息、给需要扫描的Bean对象做注解标记、扫描Class对象摘取
Bean 注册的基本信息,组装注册信息、注册成 Bean对象。那么在这些条件元素的支撑下,就可以实现出通过自定义注解和配置扫描路径的情况下,完成
Bean 对象的注册。除此之外再顺带解决一个配置中占位符属性的知识点,比如可以通过 ${token} 给 Bean 对象注入进去属性信息,那么这个操作需要用到
BeanFactoryPostProcessor,因为它可以处理 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改
BeanDefinition 属性的机制
而实现这部分内容是为了后续把此类内容结合到自动化配置处理中。整体设计结构如下图:

结合bean的生命周期,包扫描只不过是扫描特定注解的类,提取类的相关信息组装成BeanDefinition注册到容器中。

在XmlBeanDefinitionReader中解析<context:component-scan />标签,扫描类组装BeanDefinition然后注册到容器中的操作在
ClassPathBeanDefinitionScanner#doScan中实现。

  • 自动扫描注册主要是扫描添加了自定义注解的类,在xml加载过程中提取类的信息,组装 BeanDefinition 注册到 Spring 容器中。
  • 所以我们会用到 <context:component-scan /> 配置包路径并在 XmlBeanDefinitionReader 解析并做相应的处理。
  • 最后还包括了一部分关于 BeanFactoryPostProcessor 的使用,因为我们需要完成对占位符配置信息的加载,所以需要使用到
    BeanFactoryPostProcessor 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,修改 BeanDefinition 的属性信息。

实现

处理占位符配置

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

  • 依赖于 BeanFactoryPostProcessor 在 Bean 生命周期的属性,可以在 Bean 对象实例化之前,改变属性信息。所以这里通过实现
    BeanFactoryPostProcessor 接口,完成对配置文件的加载以及摘取占位符中的在属性文件里的配置信息。
  • 这样就可以把提取到的配置信息放置到属性配置中了,
    buffer.replace(startIdx, stopIdx + 1, propVal); propertyValues.addPropertyValue

定义拦截注解

注解1: lqf.springframework.context.annotation.Scope
注解2: lqf.springframework.stereotype.Component

处理对象扫描装配

源码1: lqf.springframework.context.annotation.ClassPathScanningCandidateComponentProvider

  • 这里先要提供一个可以通过配置路径 basePackage=lqf.springframework.test.bean,解析出 classes 信息的工具方法
    findCandidateComponents,通过这个方法就可以扫描到所有 @Component 注解的 Bean 对象了。

源码2: lqf.springframework.context.annotation.ClassPathBeanDefinitionScanner

  • ClassPathBeanDefinitionScanner 是继承自 ClassPathScanningCandidateComponentProvider 的具体扫描包处理的类,在 doScan
    中除了获取到扫描的类信息以后,还需要获取 Bean 的作用域和类名,如果不配置类名基本都是把首字母缩写。

解析xml中调用扫描

源码: lqf.springframework.beans.factory.xml.XmlBeanDefinitionReader

  • 关于 XmlBeanDefinitionReader 中主要是在加载配置文件后,处理新增的自定义配置属性 component-scan,解析后调用 scanPackage
    方法,其实也就是我们在 ClassPathBeanDefinitionScanner#doScan 功能。
  • 另外这里需要注意,为了可以方便的加载和解析xml,XmlBeanDefinitionReader 已经全部替换为 dom4j 的方式进行解析处理。

总结

  • 通过整篇的内容实现可以看出来,目前的功能添加其实已经不复杂了,都是在 IOC 和 AOP 核心的基础上来补全功能。这些补全的功能也是在完善
    Bean 的生命周期,让整个功能使用也越来越容易。
  • 在你不断的实现着 Spring 的各项功能时,也可以把自己在平常使用 Spring 的一些功能想法融入进来,比如像 Spring
    是如何动态切换数据源的,线程池是怎么提供配置的,这些内容虽然不是最基础的核心范围,但也非常重要。

14. 通过注解注入属性信息

工程结构

lqf-spring-step-14
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── Advisor.java
│   │           │   ├── BeforeAdvice.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodBeforeAdvice.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── PointcutAdvisor.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   ├── AspectJExpressionPointcut.java
│   │           │   │   └── AspectJExpressionPointcutAdvisor.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       ├── ProxyFactory.java
│   │           │       ├── ReflectiveMethodInvocation.java
│   │           │       ├── adapter
│   │           │       │   └── MethodBeforeAdviceInterceptor.java
│   │           │       └── autoproxy
│   │           │           └── DefaultAdvisorAutoProxyCreator.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── PropertyPlaceholderConfigurer.java
│   │           │       ├── annotation
│   │           │       │   ├── Autowired.java
│   │           │       │   ├── AutowiredAnnotationBeanPostProcessor.java
│   │           │       │   ├── Qualifier.java
│   │           │       │   └── Value.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   ├── InstantiationAwareBeanPostProcessor.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── annotation
│   │           │   │   ├── ClassPathBeanDefinitionScanner.java
│   │           │   │   ├── ClassPathScanningCandidateComponentProvider.java
│   │           │   │   └── Scope.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.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
│   │           ├── stereotype
│   │           │   └── Component.java
│   │           └── util
│   │               ├── ClassUtils.java
│   │               └── StringValueResolver.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           └── service
    │               ├── IUserService.java
    │               ├── UserDao.java
    │               └── UserService.java
    └── resources
        ├── spring.xml
        └── token.properties

自动扫描注入占位符配置和对象的类关系,如图:

  • 在整个类图中以围绕实现接口 InstantiationAwareBeanPostProcessor 的类 AutowiredAnnotationBeanPostProcessor 作为入口点,被
    AbstractAutowireCapableBeanFactory创建 Bean 对象过程中调用扫描整个类的属性配置中含有自定义注解
    ValueAutowiredQualifier,的属性值。
  • 这里稍有变动的是关于属性值信息的获取,在注解配置的属性字段扫描到信息注入时,包括了占位符从配置文件获取信息也包括 Bean
    对象,Bean 对象可以直接获取,但配置信息需要在 AbstractBeanFactory 中添加新的属性集合 embeddedValueResolvers,由
    PropertyPlaceholderConfigurer#postProcessBeanFactory 进行操作填充到属性集合中。

设计

在完成 Bean 对象的基础功能后,后续陆续添加的功能都是围绕着 Bean 的生命周期进行的,比如修改 Bean 的定义
BeanFactoryPostProcessor,处理 Bean 的属性要用到 BeanPostProcessor,完成个性的属性操作则专门继承 BeanPostProcessor
提供新的接口,因为这样才能通过 instanceof 判断出具有标记性的接口。所以关于 Bean 等等的操作,以及监听 Aware、获取
BeanFactory,都需要在 Bean 的生命周期中完成。在设计属性和 Bean 对象的注入时候,也会用到 BeanPostProcessor 来完成在设置 Bean
属性之前,允许 BeanPostProcessor 修改属性值。整体设计结构如下图:

  • 要处理自动扫描注入,包括属性注入、对象注入,则需要在对象属性 applyPropertyValues 填充之前 ,把属性信息写入到
    PropertyValues 的集合中去。这一步的操作相当于是解决了以前在 spring.xml 配置属性的过程。
  • 而在属性的读取中,需要依赖于对 Bean 对象的类中属性的配置了注解的扫描,field.getAnnotation(Value.class);
    依次拿出符合的属性并填充上相应的配置信息。
  • 关于 @Autowired 对于对象的注入,其实这一个和属性注入的唯一区别是对于对象的获取 beanFactory.getBean(fieldType)
    ,其他就没有什么差一点了。
  • 当所有的属性被设置到 PropertyValues 完成以后,接下来就到了创建对象的下一步,属性填充,而此时就会把我们一一获取到的配置和对象填充到属性上,也就实现了自动注入的功能。

实现

把读取到属性填充到容器

定义解析字符串接口

源码: lqf.springframework.util.StringValueResolver

  • 接口 StringValueResolver 是一个解析字符串操作的接口

填充字符串

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

  • 在解析属性配置的类 PropertyPlaceholderConfigurer
    中,最主要的其实就是这行代码的操作 beanFactory.addEmbeddedValueResolver(valueResolver) 这是把属性值写入到了
    AbstractBeanFactory 的 embeddedValueResolvers 中。
  • embeddedValueResolvers 是 AbstractBeanFactory 类新增加的集合 List<StringValueResolver> embeddedValueResolvers String
    resolvers to apply e.g. to annotation attribute values

自定义属性注入注解

自定义注解,Autowired、Qualifier、Value

注解1: lqf.springframework.beans.factory.annotation.Autowired
注解2: lqf.springframework.beans.factory.annotation.Qualifier
注解3: lqf.springframework.beans.factory.annotation.Value

  • 个注解在日常使用 Spring 也是非常常见的,注入对象、注入属性,而 Qualifier 一般与 Autowired 配合使用。

扫描自定义注解

源码: lqf.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

  • AutowiredAnnotationBeanPostProcessor 是实现接口 InstantiationAwareBeanPostProcessor 的一个用于在 Bean
    对象实例化完成后,设置属性操作前的处理属性信息的类和操作方法。
  • 核心方法 postProcessPropertyValues,主要用于处理类含有 @Value、@Autowired 注解的属性,进行属性信息的提取和设置。
  • 这里需要注意一点因为我们在 AbstractAutowireCapableBeanFactory 类中使用的是 CglibSubclassingInstantiationStrategy
    进行类的创建,所以在 AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 中需要判断是否为 CGlib
    创建对象,否则是不能正确拿到类信息的。

向BeanFactory中注册AutowiredAnnotationBeanPostProcessor

源码: lqf.springframework.context.annotation.ClassPathBeanDefinitionScanner

  • 由于AutowiredAnnotationBeanPostProcessor并没有标注@Component,所以是无法在类扫描时注入到beanFactory中的,此处需要我们手动进行注册。

在Bean的生命周期中调用属性注入

  • AbstractAutowireCapableBeanFactory#createBean 方法中有这一条新增加的方法调用,就是在设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值 的操作 applyBeanPostProcessorsBeforeApplyingPropertyValues
  • applyBeanPostProcessorsBeforeApplyingPropertyValues 方法中,首先就是获取已经注入的 BeanPostProcessor 集合并从中筛选出继承接口
    InstantiationAwareBeanPostProcessor 的实现类。
  • 调用相应的 postProcessPropertyValues
    方法以及循环设置属性值信息,beanDefinition.getPropertyValues().addPropertyValue(propertyValue);

总结

  • 从整个注解信息扫描注入的实现内容来看,我们一直是围绕着在 Bean 的生命周期中进行处理,就像 BeanPostProcessor 用于修改新实例化
    Bean 对象的扩展点,提供的接口方法可以用于处理 Bean 对象实例化前后进行处理操作。而有时候需要做一些差异化的控制,所以还需要继承
    BeanPostProcessor 接口,定义新的接口 InstantiationAwareBeanPostProcessor 这样就可以区分出不同扩展点的操作了。
  • 接口用 instanceof 判断,注解用 Field.getAnnotation(Value.class);
    获取,都是相当于在类上做的一些标识性信息,便于可以用一些方法找到这些功能点,以便进行处理。所以在我们日常开发设计的组件中,也可以运用上这些特点。

15. 给代理对象的属性设置值

工程结构

lqf-spring-step-15
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── Advisor.java
│   │           │   ├── BeforeAdvice.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodBeforeAdvice.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── PointcutAdvisor.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   ├── AspectJExpressionPointcut.java
│   │           │   │   └── AspectJExpressionPointcutAdvisor.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       ├── ProxyFactory.java
│   │           │       ├── ReflectiveMethodInvocation.java
│   │           │       ├── adapter
│   │           │       │   └── MethodBeforeAdviceInterceptor.java
│   │           │       └── autoproxy
│   │           │           └── DefaultAdvisorAutoProxyCreator.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── PropertyPlaceholderConfigurer.java
│   │           │       ├── annotation
│   │           │       │   ├── Autowired.java
│   │           │       │   ├── AutowiredAnnotationBeanPostProcessor.java
│   │           │       │   ├── Qualifier.java
│   │           │       │   └── Value.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   ├── InstantiationAwareBeanPostProcessor.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── annotation
│   │           │   │   ├── ClassPathBeanDefinitionScanner.java
│   │           │   │   ├── ClassPathScanningCandidateComponentProvider.java
│   │           │   │   └── Scope.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.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
│   │           ├── stereotype
│   │           │   └── Component.java
│   │           └── util
│   │               ├── ClassUtils.java
│   │               └── StringValueResolver.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           └── service
    │               ├── IUserService.java
    │               ├── UserDao.java
    │               ├── UserService.java
    │               └── UserServiceBeforeAdvice.java
    └── resources
        ├── spring.xml
        └── token.properties

在Bean的生命周期中创建代理对象的类关系,如图

  • 虽然要完成的是关于代理对象中属性的填充问题,但实际解决的思路是处理在 Bean
    的生命周期中合适的位置(初始化 initializeBean)中处理代理类的创建。
  • 主要包括:DefaultAdvisorAutoProxyCreator 类创建代理对象的操作放置在 postProcessAfterInitialization 方法中以及对应在
    AbstractAutowireCapableBeanFactory 完成初始化方法的调用操作。
  • 在 Spring 框架中,AbstractAutowireCapableBeanFactory 类里使用的是 CglibSubclassingInstantiationStrategy
    创建对象,所以有需要判断对象获取接口的方法中,也都需要判断是否为
    CGlib创建,否则是不能正确获取到接口的。如:ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;

设计

按照创建代理对象的操作 DefaultAdvisorAutoProxyCreator 实现的 InstantiationAwareBeanPostProcessor 接口,原本在 Before
中的操作,则需要放到 After 中处理。整体设计如下:

  • 在创建 Bean 对象 createBean 的生命周期中,有一个阶段是在 Bean 对象属性填充完成以后,执行 Bean 的初始化方法和
    BeanPostProcessor 的前置和后置处理方法。
  • 在 DefaultAdvisorAutoProxyCreator 用于创建代理对象的操作中,需要把创建操作从 postProcessBeforeInstantiation 方法中迁移到
    postProcessAfterInitialization,这样才能满足 Bean 属性填充后的创建操作。

实现

判断CGlib对象

源码: lqf.springframework.aop.TargetSource

  • 在 TargetSource#getTargetClass 是用于获取 target 对象的接口信息的,那么这个 target 可能是 JDK代理
    创建也可能是 CGlib创建,为了保证都能正确的获取到结果,这里需要增加判读 ClassUtils.isCglibProxyClass(clazz)

迁移创建AOP代理方法

源码: lqf.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator

  • 关于 DefaultAdvisorAutoProxyCreator 类的操作主要就是把创建 AOP 代理的操作从 postProcessBeforeInstantiation 移动到
    postProcessAfterInitialization 中去。
  • 通过设置一些 AOP 的必备参数后,返回代理对象 new ProxyFactory(advisedSupport).getProxy() 这个代理对象中就包括间接调用了
    TargetSource 中对 getTargetClass() 的获取。

在Bean的生命周期中初始化执行

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

  • 在 AbstractAutowireCapableBeanFactory#createBean 方法中,其实关注点就在于 initializeBean ->
    applyBeanPostProcessorsAfterInitialization 这一块逻辑的调用,最终完成 AOP 代理对象的创建操作。

总结

  • 核心知识内容主要是完善了 Bean 的生命周期,在创建类的操作中完成代理对象的创建,通过这样的方式就可以让代理对象中的属性也可以随着创建过程被填充进去。
  • 除了核心功能的实现外也要关注到对象的初始化操作是
    CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy,这两种方式中的 CGlib 创建对象,会影响到很多地方用于接口获取的操作,因为
    CGlib 创建对象走的是 ASM 字节码生成的操作,所以和普通的 JDK 代理生成对象是不一样,需要注意。

16. 通过三级缓存解决循环依赖

工程结构

lqf-spring-step-16
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── Advisor.java
│   │           │   ├── BeforeAdvice.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodBeforeAdvice.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── PointcutAdvisor.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   ├── AspectJExpressionPointcut.java
│   │           │   │   └── AspectJExpressionPointcutAdvisor.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       ├── ProxyFactory.java
│   │           │       ├── ReflectiveMethodInvocation.java
│   │           │       ├── adapter
│   │           │       │   └── MethodBeforeAdviceInterceptor.java
│   │           │       └── autoproxy
│   │           │           └── DefaultAdvisorAutoProxyCreator.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── ObjectFactory.java
│   │           │       ├── PropertyPlaceholderConfigurer.java
│   │           │       ├── annotation
│   │           │       │   ├── Autowired.java
│   │           │       │   ├── AutowiredAnnotationBeanPostProcessor.java
│   │           │       │   ├── Qualifier.java
│   │           │       │   └── Value.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   ├── InstantiationAwareBeanPostProcessor.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── annotation
│   │           │   │   ├── ClassPathBeanDefinitionScanner.java
│   │           │   │   ├── ClassPathScanningCandidateComponentProvider.java
│   │           │   │   └── Scope.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.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
│   │           ├── stereotype
│   │           │   └── Component.java
│   │           └── util
│   │               ├── ClassUtils.java
│   │               └── StringValueResolver.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           └── bean
    │               ├── Husband.java
    │               ├── HusbandMother.java
    │               ├── IMother.java
    │               ├── SpouseAdvice.java
    │               └── Wife.java
    └── resources
        ├── spring.xml
        └── token.properties

处理循环依赖核心流程的类关系的操作过程包括:

  • 循环依赖的核心功能实现主要包括 DefaultSingletonBeanRegistry
    提供三级缓存:singletonObjectsearlySingletonObjectssingletonFactories
    ,分别存放成品对象、半成品对象和工厂对象。同时包装三个缓存提供方法:getSingleton、registerSingleton、addSingletonFactory,这样使用方就可以分别在不同时间段存放和获取对应的对象了。
  • 在 AbstractAutowireCapableBeanFactory 的 doCreateBean 方法中,提供了关于提前暴露对象的操作,addSingletonFactory( beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));
    以及后续获取对象和注册对象的操作, exposedObject = getSingleton(beanName);、registerSingleton(beanName, exposedObject);
    经过这样的处理就可以完成对复杂场景循环依赖的操作。
  • 另外在 DefaultAdvisorAutoProxyCreator 提供的切面服务中,也需要实现接口 InstantiationAwareBeanPostProcessor 新增的
    getEarlyBeanReference 方法,便于把依赖的切面对象也能存放到三级缓存中,处理对应的循环依赖。

设计

按照 Spring
框架的设计,用于解决循环依赖需要用到三个缓存,这三个缓存分别存放了成品对象半成品对象(未填充属性值)代理对象
分阶段存放对象内题。

这里我们需要知道一个核心的原理,就是用于解决循环依赖就必须是三级缓存呢,二级行吗?一级可以不?其实都能解决,只不过 Spring
框架的实现要保证几个事情,如只有一级缓存处理流程没法拆分,复杂度也会增加,同时半成品对象可能会有空指针异常。而将半成品与成品对象分开,处理起来也更加优雅、简单、易扩展。另外
Spring 的两大特性中不仅有 IOC 还有 AOP,也就是基于字节码增强后的方法,该存放到哪,而三级缓存最主要,要解决的循环依赖就是对
AOP 的处理,但如果把 AOP 代理对象的创建提前,那么二级缓存也一样可以解决。但是,这就违背了 Spring 创建对象的原则,Spring
更喜欢把所有的普通 Bean 都初始化完成,在处理代理对象的初始化。

可以先尝试仅适用一级缓存来解决循环依赖,通过这样的方式从中学习到处理循环依赖的最核心原来,也就是那20%的地方。

  • 如果仅以一级缓存解决循环依赖,那么在实现上可以通过在A对象 newInstance 创建且未填充属性后,直接放入缓存中。
  • A对象的属性填充B对象时,如果缓存中不能获取到B对象,则开始创建B对象,同样创建完成后,把B对象填充到缓存中去。
  • 接下来就开始对B对象的属性进行填充,恰好这会可以从缓存中拿到半成品的A对象,那么这个时候B对象的属性就填充完了。
  • 最后返回来继续完成A对象的属性填充,把实例化后并填充了属性的B对象赋值给A对象的b属性,这样就完成了一个循环依赖操作。

按照目前实现的 Spring 框架,是可以满足一个基本需求的,但如果你配置了A、B两个Bean对象互相依赖,那么立马会抛出
java.lang.StackOverflowError,为什么呢?因为A创建时需要依赖B创建,而B的创建又依赖于A创建,就这样死循环了。

而这个循环依赖基本也可以说是 Spring 中非常经典的实现了,所要解决的场景主要有以下三种情况:

  • 循环依赖主要分为这三种,自身依赖于自身、互相循环依赖、多组循环依赖。
  • 但无论循环依赖的数量有多少,循环依赖的本质是一样的。就是你的完整创建依赖于我,而我的完整创建也依赖于你,但我们互相没法解耦,最终导致依赖创建失败。
  • 所以需要 Spring 提供了除了构造函数注入和原型注入外的,setter 循环依赖注入解决方案。

实现

设置三级缓存

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

  • 在用于提供单例对象注册的操作的 DefaultSingletonBeanRegistry 类中,共有三个缓存对象的属性;
    singletonObjects、earlySingletonObjects、singletonFactories,如它们的名字一样,用于存放不同类型的对象(单例对象、早期的半成品单例对象、单例工厂对象)。
  • 紧接着在这三个缓存对象下提供了获取、添加和注册不同对象的方法,包括:getSingleton、registerSingleton、addSingletonFactory,其实后面这两个方法都比较简单,主要是
    getSingleton 的操作,它是在一层层处理不同时期的单例对象,直至拿到有效的对象。

提前暴露对象

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

  • 在 AbstractAutowireCapableBeanFactory#doCreateBean 的方法中主要是扩展了对象的提前暴露addSingletonFactory
    了,和单例对象的获取getSingleton以及注册操作registerSingleton
  • 这里提到一点 getEarlyBeanReference 就是定义在如 AOP 切面中这样的代理对象,可以参考源码中接口
    InstantiationAwareBeanPostProcessor#getEarlyBeanReference 方法的实现。

总结

  • Spring 中所有的功能都是以解决 Java 编程中的特性而存在的,就像我们本章节处理的循环依赖,如果没有 Spring
    框架的情况下,可能我们也会尽可能避免写出循环依赖的操作,因为在没有经过加工处理后,这样的依赖关系肯定会报错的。

在解决循环依赖的核心流程中,主要是提前暴露对象的设计,以及建立三级缓存的数据结构来存放不同时期的对象,如果说没有如切面和工厂中的代理对象,那么二级缓存也就可以解决了,哪怕是只有一级缓存。但为了设计上的合理和可扩展性,所以创建了三级缓存来放置不同时期的对象。

17. 数据类型转换工厂设计实现

工程结构

lqf-spring-step-17
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── Advisor.java
│   │           │   ├── BeforeAdvice.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodBeforeAdvice.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── PointcutAdvisor.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   ├── AspectJExpressionPointcut.java
│   │           │   │   └── AspectJExpressionPointcutAdvisor.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       ├── ProxyFactory.java
│   │           │       ├── ReflectiveMethodInvocation.java
│   │           │       ├── adapter
│   │           │       │   └── MethodBeforeAdviceInterceptor.java
│   │           │       └── autoproxy
│   │           │           └── DefaultAdvisorAutoProxyCreator.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── ObjectFactory.java
│   │           │       ├── PropertyPlaceholderConfigurer.java
│   │           │       ├── annotation
│   │           │       │   ├── Autowired.java
│   │           │       │   ├── AutowiredAnnotationBeanPostProcessor.java
│   │           │       │   ├── Qualifier.java
│   │           │       │   └── Value.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   ├── InstantiationAwareBeanPostProcessor.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── annotation
│   │           │   │   ├── ClassPathBeanDefinitionScanner.java
│   │           │   │   ├── ClassPathScanningCandidateComponentProvider.java
│   │           │   │   └── Scope.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.java
│   │           │   └── support
│   │           │       ├── AbstractApplicationContext.java
│   │           │       ├── AbstractRefreshableApplicationContext.java
│   │           │       ├── AbstractXmlApplicationContext.java
│   │           │       ├── ApplicationContextAwareProcessor.java
│   │           │       ├── ClassPathXmlApplicationContext.java
│   │           │       └── ConversionServiceFactoryBean.java
│   │           ├── core
│   │           │   ├── convert
│   │           │   │   ├── ConversionService.java
│   │           │   │   ├── converter
│   │           │   │   │   ├── Converter.java
│   │           │   │   │   ├── ConverterFactory.java
│   │           │   │   │   ├── ConverterRegistry.java
│   │           │   │   │   └── GenericConverter.java
│   │           │   │   └── support
│   │           │   │       ├── DefaultConversionService.java
│   │           │   │       ├── GenericConversionService.java
│   │           │   │       └── StringToNumberConverterFactory.java
│   │           │   └── io
│   │           │       ├── ClassPathResource.java
│   │           │       ├── DefaultResourceLoader.java
│   │           │       ├── FileSystemResource.java
│   │           │       ├── Resource.java
│   │           │       ├── ResourceLoader.java
│   │           │       └── UrlResource.java
│   │           ├── stereotype
│   │           │   └── Component.java
│   │           └── util
│   │               ├── ClassUtils.java
│   │               ├── NumberUtils.java
│   │               └── StringValueResolver.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           ├── bean
    │           │   └── Husband.java
    │           └── converter
    │               ├── ConvertersFactoryBean.java
    │               ├── StringToIntegerConverter.java
    │               └── StringToLocalDateConverter.java
    └── resources
        ├── spring.xml
        └── token.properties

设计

如果把看上去一个简单的类型转换操作抽象成框架,那么它就需要一个标准的接口,谁实现这个接口就具备类型转换的具体实现,提供类型转换的能力。那么在有了这样接口后,还需要类型转换服务的注册、工厂等内容,才可以把类型转换抽象成一个组件服务。整体设计结构如下图:

  • 首先从工厂出发,需要实现一个 ConversionServiceFactoryBean 来对类型转换服务进行操作。
  • 而实现类型转换的服务,需要定义 Converter 转换类型、ConverterRegistry 注册类型转换功能,另外转换类型的操作较多,所以这里也会需要定义一个类型转换工厂
    ConverterFactory 各个具体的转换操作来实现这个工厂接口。

实现

定义类型转换接口

类型转换处理接口: lqf.springframework.core.convert.converter.Converter
类型转换工厂: lqf.springframework.core.convert.converter.ConverterFactory
类型转换注册接口: lqf.springframework.core.convert.converter.ConverterRegistry

  • Converter、ConverterFactory、ConverterRegistry,都是用于自定义类型转换操作的相关接口,后续所有的实现都需要围绕这些接口来实现,具体的代码功能可以进行调试验证。

实现类型转换服务

类型转换服务: lqf.springframework.core.convert.support.DefaultConversionService

  • DefaultConversionService 是继承 GenericConversionService 的实现类,而 GenericConversionService 实现了
    ConversionService,ConverterRegistry 两个接口,用于 canConvert 判断和转换接口 convert 操作。

创建类型转换工厂

类型转换工厂: lqf.springframework.context.support.ConversionServiceFactoryBean

  • 有了 FactoryBean 的实现就可以完成工程对象的操作,可以提供出转换对象的服务 GenericConversionService, 另外在
    afterPropertiesSet 中调用了注册转换操作的类。最终这个类会被配置到 spring.xml 中在启动的过程加载。

类型转换服务使用

类型转换服务使用: lqf.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

  • 在 AbstractAutowireCapableBeanFactory#applyPropertyValues 填充属性的操作中,具体使用了类型转换的功能。
  • 在 AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 也有同样的属性类型转换操作。

总结

  • 此处实现的类型转换操作如果只是功能性的开发,就像自己承接的需求那样,可能只是简单的if判断就搞定了,但是放在一个成熟的框架中要考虑的是可复用性、
    可拓展性,所以会看到接口的定义、工厂的使用等等设计模式在这里面体现。