Spring源码(1)-整体架构


一、Spring 整体架构

到了 Spring 5.0 时代,其模块大约有 20 个,如图:

image

这些模块被总结为以下几部分。

1、Core Container

Core Container(核心容器)包含 Core 、Beans 、Context 和 Expression Language 四个模块。

  • Core 模决主要包含 Spring 框架的核心工具类,是其他组件的基本核心。如动态代理相关的 asm、cglib,以及各种 Utils,StringUtils、CollectionUtils。
  • Beans 模块包含访问配置文件、创建和管理 bean 以及进行 IoC/DI 操作相关的所有类。如:BeanFactory、BeanDefinitions 等。
  • Context 模块构建于 Core 和Beans 模块基础之上,其继承了 Beans 的特性,为Spring 核心提供了大量扩展。ApplicationContext 接口是 Context 模块的核心。
  • Expression Language 模块提供了强大的表达式语言。就是在远古 JSP 时期使用的 EL 表达式。

2、Data Access/Integration

Data Access/Integration 包含 JDBC 、ORM 、OXM、JMS 和 Transaction 模块。

  • JDBC 模块提供了一个JDBC 抽象层,用来适配所有的数据库厂商。这个模块包含了 Spring 对 JDBC 数据访问进行封装的所有类。
  • ORM 模块提供了几种常用的对象关系映射框架,如 JPA 、Hibernate 、iBatis 。
  • OXM 模块提供了一个对ObjecνXML 映射实现的抽象层。
  • JMS (Java Messaging Service)模块主要包含一些生产和消费消息的特性。
  • Transaction 模块支持编程和声明性的事务管理。

3、Web

Web 层包含了Web 、Servlet 、WebSocket、Porlet 模块。

  • Web 模块:提供了基础的面向Web 的集成特性。例如,多文件上传。
  • Servlet 模块:该模块包含Spring 的model-view-controller (MVC)实现。
  • WebSocket 模块:提供 WebSocket 协议支持。
  • Porlet 模块:提供了用于 Portlet 环境和 Servlet 模块的 MVC 的实现

4、AOP

AOP 模块提供了一个符合 AOP 联盟标准的面向切面编程实现,它让你可以定义例如方法拦截器和切点,从而将逻辑代码分开,降低它们之间的耦合性。

  • Aspects 模块提供了对AspectJ 的集成支持。
  • Instrumentation 模块提供了class instrumentation 支持和classloader 实现,使得可以在特定的应用服务器上使用。
  • Messaging 模块:对消息通信集成提供了广泛的支持,及提供简化 JMS API 的使用到异步接收消息的完整基础结构。

5、Test

Test 模块支持使用 JUnit 和TestNG 对 Spring 组件进行测试。

二、图解执行流程

1、Bean的解析流程

image-20211229211606135

如图所示,就是通过 解析器,对我们的 XML 文件或者注解进行解析,最后将这些信息封装在 BeanDefinition 类中,并通过 BeanDefinitionRegistry 接口将这些信息 注册 起来,放在 beanDefinitionMap 变量中, key : beanName , value :BeanDefinition

简单看看 BeanDefinition 中的属性叭

(1)BeanDefinition

  • beanClass : bean 的类型 ,实例化时用的
  • scope : 作用范围有 singletonprototype
  • isLazy : 懒加载 ,true 的话 会在 getBean 时生成,而且 scope 的 prototype 无效,false 在 Spring 启动过程中直接生成
  • initMethodName : 初始化方法,当然是初始化时调用
  • primary : 主要的,有多个 Bean 时使用它
  • dependsOn : 依赖的Bean,必须等依赖Bean 创建好才可以创建

PS: @Component ,@Bean ,都会被解析成 BeanDefinition

(2)反射

有了原料后呢,咱们再来看看这个 工厂 BeanFactory

先简单想一想这个工厂要怎么创建这个 Bean 呢?

没错,肯定就是这个 反射

那么,结合我们从原料中获取的重要属性之一的 beanClass ,我们可以画出这么一张图

image-20211229211825162

2、IOC容器

(3)BeanFactory

先来看看 作为IOC 容器的根接口 的 BeanFactory 提供了什么方法吧

public interface BeanFactory {

    // 对 FactoryBean 的转义定义,因为如果使用 bean 的名字检索 FactoryBean 得到的对象是工厂生成的对象,
    // 如果需要得到工厂本身,需要转义(FactoryBean 在后续会详细介绍)
    String FACTORY_BEAN_PREFIX = "&";

    // 根据 bean 的名字,获取在容器中 bean 实例
    Object getBean(String name) throws BeansException;

    //根据 bean 的名字和 Class 类型来得到 bean 实例,增加了类型安全验证机制。
    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    // 提供对 bean 的检索,看看是否在容器有这个名字的 bean
    boolean containsBean(String name);

    // 根据 bean 名字,判断这个 bean 是不是单例
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    // 根据 bean 名字,判断这个 bean 是不是原型
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    // 根据 bean 名字,判断是否与指定的类型匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    // 得到 bean 实例的 Class 类型
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    // 得到bean 的别名,如果根据别名检索,那么其原名也会被检索出来
    String[] getAliases(String name);
}

主要是这个 getBean 方法,以及 别名获取类型获取 方法和其他一些判断方法如 :单例多例类型匹配包含bean

看源码的时候,一般就直接看这个默认接口 DefaultListableBeanFactory

BeanFactory 结构

(4)FactoryBean

FactoryBean ,它本身就是个 Bean,算是小工厂 ,归 BeanFactory 这个大工厂管理的。

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

它就只有三个方法

  1. getObject() 获取对象
  2. isSingleton() 是否单例对象
  3. getObjectType() 返回的是 Bean 对象的类型

相比大工厂 BeanFactory 少了特别多东西,没有严格的 Bean 生命周期流程

  • FacotryBean 对象本身也是一个Bean,是一个小工厂,可以生产另外的 Bean

  • BeanFactory 是 Spring 容器的根接口,是大工厂,生产各种各样的Bean

  • beanName 就是正常对象

  • “&”+beanName , 获取的是实现了该接口的 FacotryBean 工厂对象

image-20211229212918177

(5)ApplicationContext

image-20211229213541581

可以看到它扩展了很多功能,除了 BeanFactory ,它还可以创建 , 获取 Bean,以及处理国际化事件获取资源

  • EnvironmentCapable 获取 环境变量 的功能,可以获取到 操作系统变量JVM 环境变量
  • ListableBeanFactory 获取所有 BeanNames,判断某个 BeanName 是否存在 BeanDefinition 对象,统计 BeanDefinition 对象,获取某个类型对应的所有 beanNames 等功能
  • HierarchicalBeanFactory 获取父 BeanFactory ,判断某个 name 是否存在 bean 对象的功能
  • MessageSource 国际化功能,获取某个国际化资源
  • ApplicationEventPublisher 事件发布功能(重点)
  • ResourcePatternResolver 加载,获取资源的功能,这里的资源可能是文件,图片 等某个URL资源都可以

还有这三个重要的类,就不一一介绍先啦

  1. ClassPathXmlApplicationContext
  2. AnnotationConfigApplicationContext
  3. FileSystemXmlApplicationContext

3、Bean的生产流程

当然,这时候出场的肯定是 IOC 啦。

我们都知道 IOC 是 控制反转 ,但是别忘了 容器 这个词,比如 容器的根接口 **BeanFactory ,容器的实现**

  1. ClassPathXmlApplicationContext
  2. AnnotationConfigApplicationContext
  3. FileSystemXmlApplicationContext

同时我们要注意这里无处不在的 后置处理器 xxxPostProcessor

这个是 Spring 中扩展性强的原因了!

我们可以在各个过程中合理应用这些 PostProcessor 来扩展,或者修改 Bean 定义信息等等

image-20211229213907035

可以看到在这个容器中,完成了 Bean 的初始化,而这个过程还有很多细节

(6)BeanFactory 后置处理器

作为 IOC 容器根接口的 BeanFactory ,有着非常高的扩展性,比如最开始获取原料 BeanDefinition 时,就出现了两个针对 BeanFactory 工厂的后置处理器

BeanDefinitionRegistryPostProcessor

通过该接口,我们可以自己掌控我们的 原料,通过 BeanDefinitionRegistry 接口去 新增删除获取我们这个 BeanDefinition

BeanFactoryPostProcessor

通过该接口,可以在 实例化对象前,对 BeanDefinition 进行修改 ,冻结预实例化单例Bean

经过上面层层阻碍后,我们最终会来到目标方法 getBean ,将原料投入生产,最终获取一个个 Bean 对象出来

那么随之而来的就是这个 Bean 的生命周期啦

4、Bean 生命周期

Bean 的创建和管理有标准化的流程

img

(7)Bean 后置处理器

在实例化 和 初始化流程中,把这个Bean 的后置处理器 BeanPostProcessor 安排上,就得到下图啦

这里留意下 实例化 有扩展点 InstantiationAwareBeanPostProcessor , 初始化 扩展点 BeanPostProcessor 就非常多

image-20211229215042426

5、AOP

那么 AOP 是在哪个步骤代理对象的呢?

image-20211229215206610

可以在 AbstractAutoProxyCreator 类中看到

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    }

    return bean;
}

  目录