导言

在Spring框架中,BeanFactory 是最基本的容器,负责依赖注入和 Bean 的生命周期管理;

ApplicationContext是建立在这个基础之上的更加丰富和完善的容器环境,不仅包含了 BeanFactory的所有功能,还扩展了很多企业级支持;

两个主要的后处理器 BeanFactoryPostProcessorBeanPostProcessor构成了Spring功能扩展的主要分支,通过介入Bean的生命周期和容器的配置处理,进一步增强了Spring容器的灵活性和功能性。

建议

对于源码的阅读,每一个类就像一个螺丝钉,一定要大致了解每个类的用处,然后再去理解源码的执行流程。

一定要重视单元测试,debug打好断点一步步跟着走一遍,当然要先理清核心类的构建思路。

悟从疑得,乐自苦生。

BeanFactory

主要负责单个bean的构建

  1. bean实例化策略 InstantiationStrategy
    • 构造函数实例化
    • 工厂方式实例化
  2. 作用域
  3. 懒加载
  4. 占位符解析(这个跟 BeanFactoryPostProcessor有关)
  5. 初始化和销毁方法
    • 三种方式:xml文件定义属性、实现接口,加注解(第三种基于 BeanPostProcessor
  6. 类型转换
  7. 循环依赖DefaultSingletonBeanRegister单例注册表)

ApplicationContext

  1. 资源管理体系的集成(资源的识别、加载、解析)

  2. 自动生命周期管理

    • 自动启动(在启动时自动创建和配置所有的bean,即时实例化)
    • 集成的两个后处理器提供更加细致灵活的管理和扩展
  3. [上下文感知](#2. ApplicationContextAware)

  4. 额外企业级支持

BeanFactoryPostProcessor

  1. [占位符解析](#3. 占位符解析)

    PropertyPlaceholderConfigurer

BeanPostProcessor

  1. [注解方式属性注入](#2. 实例化bean,@Value注解扫描,为bean注入属性)

    AutowiredAnnotationBeanPostProcessor

  2. 注解方式生命周期回调

    CommonAnnotationBeanPostProcessor

    @PostConstruct@PreDestroy

  3. 上下文感知

    ApplicationContextAwareProcessor

  4. AOP动态代理

    DefaultAdvisorAutoProxyCreator

生命周期回调:Spring 允许Bean在关键生命周期点执行自定义的逻辑,如初始化后或销毁前。

接口

1. 接口的多态性

问题:Java中,一个接口,两个实现了接口的类,这两个类不相关,一个类实现了接口中的方法,一个类调用了接口中的方法,为什么调用接口方法的类能够调用到另一个类中对该接口的实现?

在Java中,多态允许一个接口引用变量来引用多种具体实现的对象,这意味着一个接口的引用可以指向任何实现了该接口的类的对象。这种特性使得程序可以在不改变接口的前提下,使用由不同类创建的对象,从而实现代码的灵活性和复用性。

2. 接口做识别功能

Spring框架中经常使用接口做识别功能

例如:Spring容器通过自动检测实现了特定接口的Bean,然后添加额外逻辑。

当然,开发者也可以借助此功能自定义额外功能扩展

例如:如果开发者想使用 BeanPostProcessor做额外功能的扩展,可以先做好逻辑,然后重写一个接口继承自 BeanPostProcessor,实现该接口的独有方法,然后以此为识别条件插入生命周期当中。

Spring-软件设计原则

1. 接口隔离原则

Spring将接口 按功能 划分的尽可能小而精简,避免了不必要的依赖和接口的臃肿。

2. 合成复用原则

Spring框架将应用程序拆分为小的可重用组件,并通过对象组合的方式将这些组件组合在一起构建应用程序。通过组件化设计,使得系统更加模块化、可维护和可扩展。

Spring-设计模式

1. 工厂模式

BeanFactoryApplicationContext使用工厂模式创建对象,不通过构造函数创建,而将职责移交给内部复杂的IoC容器,大大增强了Spring的模块性、扩展性与灵活性。

二者还将bean的创建细节封装在容器内部,大大简化了bean的配置与管理,使开发者更专注于业务逻辑的实现。

2. 单例模式

每个单例bean只被创建一次,在后续重用。

3. 模板方法模式

定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

在Bean工厂中模板方法模式运用的非常彻底,调用者直接调用父类的方法,父类方法的具体实现延伸到了子类中来实现。

4. 建造者模式

将一个复杂对象的构建拆解开来,使用指挥者类来调用方法创建对象。doCreateBean()refresh()方法体现了分步创建复杂对象的思想,将复杂对象的构建拆解开来,通过不同的子过程来”建造”一个完整的Bean对象,用指挥者指挥建造者的方法来调用方法,清晰明了。

5. 外观模式

最典型的就是 BeanFactorygetBean(),封装内部的复杂逻辑,对外只暴露简单的接口。

另一个例子是 ApplicationContext,它集成了 BeanFactory功能并提供更高级的功能(如事件发布、国际化支持等),同样为复杂的底层实现提供了简单的调用接口。

6. 策略模式

Spring的实例化策略、资源加载器、AOP代理、类型转换等都可以根据传入参数的不同在运行时决定使用的策略,实现策略的切换。

这种模式解耦了算法的选择和实施的过程,使得算法可以独立于使用它们的客户端变化。策略模式的应用帮助框架提高了灵活性和可扩展性,使得开发者可以根据具体的需求轻松地切换和配置不同的行为。

7. 适配器模式

[bean的销毁方法](#3. 适配器模式的应用):DisposableBeanAdapter将不同的销毁机制适配到一个统一的接口

注解的解析&类型转换:都通过内部类的方式将不同接口的子实现类结合到一起

8. 观察者模式

事件和监听机制

9. 代理模式

AOP动态代理

10. 责任链模式

拦截器链

最简单的bean容器

image-20240506144409831

DefaultListableBeanFactory 是 Spring IoC 容器的默认实现之一,具有注册和管理 Bean 定义、创建和管理 Bean 实例、管理 Bean 生命周期等功能。

BeanFactory的子实现接口:

  • HierarchicalBeanFactory用于表示具有层次结构的 BeanFactory
  • ConfigurableBeanFactory用于表示可配置的 BeanFactory
  • AutowireCapableBeanFactory 用于表示可自动装配的 BeanFactory。可以实现对 Bean 的自动装配,包括按名称、按类型、构造器自动装配等。
  • ListableBeanFactory用于表示可列举的 BeanFactory。提供了对 Bean 列表进行操作的方法,而不仅仅是获取单个 Bean 实例。
  • ConfigurableListableBeanFactory继承自以上三个接口,可以实现对 BeanFactory配置和 Bean 列表操作的同时,还支持对 Bean 的自动装配。

Bean实例化策略

InstantiationStrategy

使用了策略模式

InstantiationStrategy接口

用于定义创建 Bean 实例的策略,例如通过调用构造函数、通过工厂方法、或者通过其他方式创建。

SimpleInstantiationStrategy

Spring 框架中的一个简单的 Bean 实例化策略,用于通过调用类的无参构造方法来创建 Bean 实例。它是默认的 Bean 实例化策略之一,在大多数情况下都可以满足需求。

CglibSubclassingInstantiationStrategy

Spring 框架中用于基于 CGLIB 进行子类化的 Bean 实例化策略,用于创建 Bean 实例的代理对象。

目前只支持无参构造实例化。

注入属性

分为两类

  • 为Bean注入普通属性
  • 为Bean注入Bean

BeanReference

Spring 框架中用于表示对其他 Bean 的引用的类,它提供了延迟解析的功能,并支持循环依赖的处理。

在 XML 配置文件中,可以使用 <ref> 元素来声明对其他 bean 的引用,而在 Spring 的内部处理过程中,这些引用将会被解析为 BeanReference 对象。

资源和资源加载器

这个也算是一个策略模式

Resource 接口是 Spring 框架中用于表示外部资源的抽象接口,它提供了统一的资源访问接口,并支持不同类型的资源以及与其他 Spring 模块的集成。

  • ClassPathResource 是 Spring 框架中用于表示类路径下资源的类。
  • FileSystemResource 是 Spring 框架中用于表示文件系统中资源的类。
  • UrlResource 是 Spring 框架中用于表示 URL 资源的类。

这三个类可以使得应用程序能够方便地访问类路径下、文件系统中、各种类型的URL的资源,而不需要关心资源的具体位置和加载方式。这样可以增加应用程序的灵活性和可移植性,同时也使得代码更加清晰和易于维护。(根据IO流获取)

ResourceLoader 是 Spring 框架中的一个接口,用于加载资源。通过它可以方便地获取各种类型的资源对象,从而实现资源的统一管理和使用。

DefaultResourceLoader 是 Spring 框架中资源加载的默认实现,提供了一种简单方便的方式来加载资源,支持多种资源类型,具有良好的扩展性和定制性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ResourceAndResourceLoaderTest {

@Test
public void testResourceLoader() throws Exception {
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();

//加载classpath下的资源
Resource resource = resourceLoader.getResource("classpath:hello.txt");
InputStream inputStream = resource.getInputStream();
String content = IoUtil.readUtf8(inputStream);
System.out.println(content);
assertThat(content).isEqualTo("hello world");

//加载文件系统资源
resource = resourceLoader.getResource("src/test/resources/hello.txt");
assertThat(resource instanceof FileSystemResource).isTrue();
inputStream = resource.getInputStream();
content = IoUtil.readUtf8(inputStream);
System.out.println(content);
assertThat(content).isEqualTo("hello world");

//加载url资源
resource = resourceLoader.getResource("https://www.baidu.com");
assertThat(resource instanceof UrlResource).isTrue();
inputStream = resource.getInputStream();
content = IoUtil.readUtf8(inputStream);
System.out.println(content);
}
}

执行流程:

  1. 使用resourceLoader.getResource根据类型返回resuorce接口实现类对象
  2. 调用resource.getInputStream获得字节输入流,然后解析

XML解析

BeanDefinitionReader 是 Spring 框架中用于读取和解析 Bean 定义信息的接口,它将外部资源中的配置信息解析为内部数据结构,并将其注册到 IoC 容器中,以便后续的 Bean 实例化和管理。

AbstractBeanDefinitionReader 是 Spring 框架中用于读取和解析 Bean 定义信息的抽象基类,提供了一些通用的方法和属性,用于封装读取外部资源和解析 Bean 定义的通用功能,并定义了一些扩展点,支持不同格式配置文件的解析和加载。

模板方法和实际执行方法,例如 loadBeanDefinitionsdoLoadBeanDefinitions,还有子类和父类方法的配合

后处理器

两个后处理器何时执行?怎么执行?

首先,二者都要被注入到Spring容器当中

1. BeanFactoryPostProcessor

bean工厂后处理器使用 getBeanOfType()获得工厂后处理器Bean,然后调用方法for循环全都执行了

2. BeanPostProcessor

bean后处理器也是先被注入,但是要等实例化bean时,在 doCreateBean()方法中被插入、调用

应用上下文

Application

变动:创建了一个context包

1. 继承体系

image-20240422163717033

2. refresh和getBean

refresh() 方法用于初始化和刷新 Spring 容器,而 getBean() 方法用于从容器中获取 Bean 实例。<span style="color:red">在实际应用中,通常是先调用 refresh() 方法初始化容器,然后再通过 getBean() 方法获取所需的 Bean 实例来进行业务操作。

例如:

这一步执行 refresh()方法(内部可能会提前执行一些 getBean()方法)

1
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:auto-proxy.xml");

这一步才执行对应的 getBean()方法

1
WorldService worldService = applicationContext.getBean("worldService", WorldService.class);

2.1 getBean从容器中获取Bean实例

  • DefaultListableBeanFactory的正常加载

    当创建容器解析文件后,Bean只是被创建和初始化,尚未被实例化。

    当用户传递名称确定要获取的bean时,才会对Bean进行实例化。

  • 具体步骤:见上面

1
2
3
4
5
6
7
8
9
@Override
public Object getBean(String name) throws BeansException {
Object bean = getSingleton(name);
if (bean != null) {
return bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return createBean(name, beanDefinition);
}

先进行判断单例池中是否存在要查找的对象,若没有,那就根据BeanDefinition实时创建一个,并添加到单例池中。

2.2_refresh初始化和刷新Spring容器

  • ClassPathXmlApplicationContext的提前加载

    通过调用 refresh() 方法,会执行 beanFactory.preInstantiateSingletons() 来提前实例化所有的单例 Bean,以提高应用程序的启动性能和响应速度。

  • 具体步骤:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @Override
    public void refresh() throws BeansException {
    /*
    1. 刷新或创建一个完整的Bean工厂对象
    这一个方法相当于DefaultListableBeanFactory的三步
    // 1. 先创建一个DefaultListableBeanFactory对象作为容器
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    // 2. 创建读取器并将容器传给它
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    // 3. 读取器从xml文件中读取bean定义,并将其加载到容器中
    beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");
    */
    refreshBeanFactory();
    // 2. 获得刚刚刷新或创建的Bean工厂实例
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // 3. 在Bean实例化之前,执行BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(beanFactory);
    // 4. BeanPostProcessor需要提前在其他bean实例化之前注册
    registerBeanPostProcessors(beanFactory);
    // 5. 提前实例化单例Bean,提高应用程序的启动性能和响应速度
    beanFactory.preInstantiateSingletons();
    }

3. 目前认为的重点

  1. 设置容器的地方要清楚,通常是 AbstractXXX抽象类
  2. getBean()refresh()的执行流程要清楚(这个明白后基本也就明白 ApplicationContextBeanFactory的区别了)
  3. 提前加载 refresh、正常加载 getBean、延时加载

初始化和销毁方法

(将初始化和销毁方法添加到doCreate生命周期中)

1. 用到的类

  1. BeanDefinition中增加了 initMethodNamedestroyMethodName

  2. XmlBeanDefinitionReader增加了对 init-methoddestroy-method属性的读取

  3. 增加了 DisposableBean接口和 InitializingBean接口

  4. ConfigurableBeanFactory接口增加了 destroySingletons销毁单例Bean方法

  5. DefaultSingletonBeanRegistry增加了存储可被销毁Bean的容器,增加并实现了注册和销毁Bean的方法

  6. 新增了 <span style="color:red">DisposableBeanAdapter类,实现了 DisposableBean接口

    该类封装了对Bean的销毁过程,用来处理Bean的销毁逻辑。

    对于销毁逻辑,运用了适配器模式和桥接模式的思想,同时实现了接口的销毁操作和自定义的销毁操作

    • 用到的适配器模式思想:允许那些没有实现 DisposableBean接口的类,通过指定一个销毁方法名来整合进Spring的生命周期管理。
  7. AbstractAutowireCapableBeanFactory通过 invokeInitMethods方法和 initializeBean方法 <span style="color:blue">将初始化操作加到了生命周期中,然后将可被销毁的bean注册到一个专门的注册表中,用来追踪需要执行销毁方法的Bean

2. 重点

对于可被销毁的bean,Spring将其专门在 doCreateBean()方法中被识别,将其注册在一个专门的集合中,用来理那些具体需要销毁操作的Bean。

这是一个用来追踪、管理和调度销毁逻辑的机制。通过这种机制,再加上 DisposableBeanAdapter和销毁方法的具体逻辑,确保每个可被销毁的Bean只被注册一次,销毁的时候也只被销毁一次。

3._适配器模式的应用

适配器模式主要用于连接两个不兼容的接口,使它们可以一起工作。在 DisposableBeanAdapter的情况下,这个模式主要体现在它允许那些没有实现 DisposableBean接口的类,通过指定一个销毁方法名来整合进Spring的生命周期管理。适配器在这里作用是允许不同类型的对象(实现了 DisposableBean和未实现的)以统一的方式进行销毁处理。将不同的销毁机制适配到一个统一的接口。

与传统适配器模式的区别

  • 接口转换:在传统的适配器模式中,适配器通常是为了转换一个已存在的接口到另一个接口,以满足客户端的期望。而在 DisposableBeanAdapter的情况中,适配的不是接口之间的直接转换,而是提供一种机制来适配那些未直接实现特定接口(这里是 DisposableBean)的类,使其能够以统一的方式被处理。
  • 逻辑增强DisposableBeanAdapter 还包含了一些逻辑判断,例如防止同名方法被重复调用的情况,这超出了传统适配器模式的简单接口转换功能。

Aware接口

重点就在一个感知,使实现了接口的类能够访问完整的 BeanFactoryApplicationContext

增加了 Aware接口、BeanFactoryAware接口、ApplicationContextAware接口

1. BeanFactoryAware

实现方式:在 initializeBean方法中判断bean是否实现了 BeanFactoryAware接口,如果实现,那就在 initializeBean方法中 执行该Bean的 setBeanFactory方法,将 BeanFactory的引用传递给Bean的成员变量,doCreate方法将 initializeBean加入实例化过程中

1
2
3
4
5
6
// AbstractAutowireCapableBeanFactory
protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
}

2._ApplicationContextAware

实现方式:通过 BeanPostProcessor,定义一个 BeanPostProcessor的实现类 ApplicationContextAwareProcessor,通过refresh方法将其添加进生命周期中,将 ApplicationConext赋给bean

1
2
3
4
5
6
7
8
// ApplicationContextAwareProcessor
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(applicationContext);
}
return bean;
}
1
2
3
4
5
6
// AbstractApplicationContext
@Override
public void refresh() throws BeansException {
//添加ApplicationContextAwareProcessor,让继承自ApplicationContextAware的bean能感知bean
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
}

设计模式:体现了建造者模式的好处,现在要添加功能,直接实现好子功能,将其添加进指挥者方法中就好,解耦,拓展性强

作用域

增加prototype的支持

  1. BeanDefiniton加属性和方法(<span style="color:red">重点,有点绕)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// BeanDefinition
/**
首先是默认值,scope默认是singleton,所以singleton=true、prototype=false
*/
public static String SCOPE_SINGLETON = "singleton";
public static String SCOPE_PROTOTYPE = "prototype";
private String scope = SCOPE_SINGLETON;
private boolean singleton = true;
private boolean prototype = false;
/**
解析xml文件后获得了开发者设置的作用域,将作用域赋值给scope,然后对应改变singleton和prototype的boolen值。
*/
public void setScope(String scope) {
this.scope = scope;
this.singleton = SCOPE_SINGLETON.equals(scope);
this.prototype = SCOPE_PROTOTYPE.equals(scope);
}
public boolean isSingleton() {
return this.singleton;
}
public boolean isPrototype() {
return this.prototype;
}
  1. XmlBeanDefinitionReader增加了解析scope的步骤
  2. 在doCreateBean方法中加了两步判断,添加单例池方法与销毁方法执行之前要先判断该Bean是否为单例,否则不执行这两个方法
1
2
3
4
5
6
7
8
9
10
11
// AbstractAutowireCapableBeanFactory
// doCreateBean方法
if (beanDefinition.isSingleton()) {
addSingleton(beanName, bean);
}
// registerDisposableBeanIfNecessary方法
if (beanDefinition.isSingleton()) {
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
  1. 在ApplicationContext提前实例化Bean之前,也加了一步该Bean是否为单例的判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// DefaultListableBeanFactory
@Override
public void preInstantiateSingletons() throws BeansException {
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
if(beanDefinition.isSingleton()){
getBean(beanName);
}
});
}
// AbstractApplicationContext
@Override
public void refresh() throws BeansException {
//1.2.3.4...
// 5. 提前实例化单例Bean,提高应用程序的启动性能和响应速度
beanFactory.preInstantiateSingletons();
}

FactoryBean

自定义一个实现了FactoryBean的工厂类,此工厂方式第一次产生的Bean实例不会存储到单例池singletonObjects中,会存储到 factoryBeanObjectCache 缓存池中。首次请求会创建一个对象并缓存该对象,后续请求将直接把返回缓存的对象存到单例池中,提高性能。

就是一种注入Bean的方法,FactoryBean接口是Spring内部为工厂方法注入提供了内部的实现,使之更规范,更高效。

代码演示(底层+应用):

1
2
3
4
5
6
// FactoryBean接口:一个用于创建特定类型对象(T)的工厂模式接口。实现这个接口允许自定义Bean的创建过程
public interface FactoryBean<T> {
// 自定义工厂中得到Bean的方法
T getObject() throws Exception;
boolean isSingleton();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// AbstractBeanFactory:支持单例注册和Bean的配置管理
// 缓存池
private final Map<String, Object> factoryBeanObjectCache = new HashMap<>();
@Override
public Object getBean(String name) throws BeansException {
Object shareInstance = getSingleton(name);
if (shareInstance != null) {
return getObjectForBeanInstance(shareInstance, name);
}
BeanDefinition beanDefinition = getBeanDefinition(name);
Object bean = createBean(name, beanDefinition);
return getObjectForBeanInstance(bean, name);
}
/**
* 从特定Bean实例中获得相应的对象
* @param beanInstance
* @param beanName
* @return
*/
protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {
Object object = beanInstance;
if (beanInstance instanceof FactoryBean) { // 获得实现了FactoryBean接口的对象
FactoryBean factoryBean = (FactoryBean) beanInstance; // 转换类型
try {
if (factoryBean.isSingleton()) {
object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = factoryBean.getObject();
this.factoryBeanObjectCache.put(beanName, object);
}
} else {
object = factoryBean.getObject();
}
} catch (Exception ex) {
throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", ex);
}
}
return object;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CarFactoryBean implements FactoryBean<Car> {
private String brand;
@Override
public Car getObject() throws Exception {
Car car = new Car();
car.setBrand(brand);
return car;
}
@Override
public boolean isSingleton() {
return true;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="car" class="org.springframework.common.CarFactoryBean">
<property name="brand" value="porsche"/>
</bean>
</beans>
1
2
3
// Test方法
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:factory-bean.xml");
Car car = applicationContext.getBean("car", Car.class);

有三种工厂方法实例化的方式,前两种只会使用,factory-bean和factory-method Bean标签底层还没看

容器事件和事件监听器

1._观察者模式

1.1 结构

主要分为四块儿:广播器、发布、事件、监听器

通俗说就是:谁要发、怎么发、发的是什么、谁接收

1.2 实现方式

广播器中创建一个存储监听器的容器,当广播器要广播事件时,遍历容器中的监听器,逐个将事件作为参数传递给监听器的 onApplicationEvent 定义当特定类型的事件发生时应该执行的行为方法

1.3 Spring对该模式的使用

利用了Spring IoC和DI的特性:

  1. 监听器类通过配置文件被Spring容器自动管理

  2. 内部将其分为两步

    • 存储监听器阶段

      解析完配置文件后,Spring提前创建监听器类,将自定义监听器存储进监听器容器中,方便后续调用

      1
      ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:event-and-event-listener.xml");
    • 发布事件 监听器接收阶段

      广播器发送事件后,Spring从监听器容器中获取监听器,并传递事件参数 执行监听器对应方法

      1
      applicationContext.publishEvent(new CustomEvent(applicationContext));
  3. Spring中内嵌了 上下文刷新事件及监听器上下文关闭事件及监听器

    这些都在AbstractApplicationContext中配置,如果你忘了,建议看着refresh方法自己过一遍(就在这个类里)

2. 广播器

  1. ApplicationEventMulticaster广播器顶层接口(聚合了ApplicationListener),实现了广播器最基础的几个方法

    1
    2
    3
    4
    5
    public interface ApplicationEventMulticaster {
    void addApplicationListener(ApplicationListener<?> listener);
    void removeApplicationListener(ApplicationListener<?> listener);
    void multicastEvent(ApplicationEvent event);
    }
  2. AbstractApplicationEventMulticaster,实现BeanFactoryAware接口、存储事件监听器对象

    1
    2
    3
    4
    5
    public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new HashSet<>();
    private BeanFactory beanFactory;
    //...
    }
  3. SimpleApplicationEventMulticaster 广播器的简单实现,主要是用来实现 将一个特定的事件广播给所有注册的监听器这个方法

    1
    2
    3
    4
    5
    6
    7
    8
    @Override // ApplicationEventMulticaster接口方法的实现
    public void multicastEvent(ApplicationEvent event) {
    for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
    if (supportsEvent(applicationListener, event)) {
    applicationListener.onApplicationEvent(event);
    }
    }
    }

3. 发布

分为两种,Spring内嵌发布和手动发布

3.1 内嵌发布

关键类在于 ApplicationContext

ApplicationContext继承了 ApplicationEventPublisherAbstractApplicationContext实现了该接口的 publishEvent发布事件方法,用来发布 ContextRefreshedEvent上下文刷新事件和 ContextClosedEvent上下文关闭事件。

3.2 手动发布

1
2
// 就是自己在Test方法中手动传入自定义事件并将其发布
applicationContext.publishEvent(new CustomEvent(applicationContext));

3.3 发布的实现过程

(见广播器第三点)

遍历容器中的监听器,逐个将事件作为参数传递给监听器的 onApplicationEvent 定义当特定类型的事件发生时应该执行的行为方法,触发该方法说明广播器成功发布,监听器也从BeanFactory中获得了想要的信息

4. 事件+监听器

都分为Spring内嵌和自定义

1
2
3
4
5
6
7
8
9
10
11
public abstract class ApplicationEvent extends EventObject {
/**
* 构造一个典型的事件(实现Application的方法)
*
* @param source 参数source:事件最初发生的对象
* @throws IllegalArgumentException 如果source是null,抛出IllegalArgumentException异常
*/
public ApplicationEvent(Object source) {
super(source);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class ApplicationContextEvent extends ApplicationEvent {
public ApplicationContextEvent(Object source) {
super(source);
}

/**
* 返回一个 ApplicationContext 类型的对象
* <p>提供一种安全和方便的方式来访问触发事件的应用程序上下文。通过这个方法,事件的处理者可以轻松获取到事件关联的 Spring 容器,进而操作容器中的各种 Bean 或查询容器的状态。</p>
* @return
*/
public final ApplicationContext getApplicationContext() {
return (ApplicationContext) getSource();
}
}
1
2
3
4
5
public class ContextClosedEvent extends ApplicationContextEvent {
public ContextClosedEvent(Object source) {
super(source);
}
}
1
2
3
4
5
6
public class ContextClosedEventListener implements ApplicationListener<ContextClosedEvent> {
@Override
public void onApplicationEvent(ContextClosedEvent event) {
System.out.println("监听上下文关闭" + this.getClass().getName());
}
}
1
2
3
4
5
public class ContextRefreshedEvent extends ApplicationContextEvent {
public ContextRefreshedEvent(Object source) {
super(source);
}
}
1
2
3
4
5
6
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("监听刷新事件:" + this.getClass().getName());
}
}
1
2
3
4
5
public class CustomEvent extends ApplicationContextEvent {
public CustomEvent(ApplicationContext source) {
super(source);
}
}
1
2
3
4
5
6
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("自定义事件监听器:打印监听器类的名称" + this.getClass().getName());
}
}

5. 实现BeanFactoryAware接口的作用

以下内容生成字ChatGPT4,截止4.24 13:29,我还没太明白

让我通过一个具体的例子来解释为什么 AbstractApplicationEventMulticaster 实现 BeanFactoryAware 接口是有用的,以及这种感知 BeanFactory 的能力如何在实际应用中发挥作用。

背景

在 Spring 的事件驱动架构中,ApplicationEventMulticaster 负责处理所有的事件发布任务,即将事件从发布者发送到所有相关的监听器。为了做到这一点,事件多播器需要知道所有注册的事件监听器。在大型应用中,监听器可能会很多,并且它们可能有不同的依赖和初始化时间。

使用场景

假设你有一个大型电商平台,其中包含一个订单服务,订单服务在创建订单后会发布一个 OrderCreatedEvent。你希望在订单创建后执行多个操作,比如发送确认邮件给用户、更新库存系统、记录订单统计信息等。每个操作由不同的服务(或监听器)处理。

实现方式

  1. 定义事件: 首先定义 OrderCreatedEvent,这个事件包含了订单的所有相关信息。
  2. 事件监听器: 你可能会定义多个监听器如 EmailNotificationListenerInventoryUpdateListenerOrderStatisticsListener 等,每个监听器监听 OrderCreatedEvent
  3. 事件多播器: 你使用 AbstractApplicationEventMulticaster 来广播 OrderCreatedEvent 到所有相关的监听器。

BeanFactoryAware 的作用

在这个场景中,AbstractApplicationEventMulticaster 需要知道所有关心 OrderCreatedEvent 的监听器。这些监听器可能是在不同的地方定义并通过 Spring 管理。AbstractApplicationEventMulticaster 实现 BeanFactoryAware 的作用就体现出来了:

  • 动态感知监听器: AbstractApplicationEventMulticaster 可以利用 BeanFactory 动态地获取所有注册为 ApplicationListener 的 Bean。这意味着无论何时添加新的监听器或移除旧的监听器,AbstractApplicationEventMulticaster 都能即时地更新其监听器列表,无需重新启动应用或重新配置。
  • 灵活的依赖注入: 有些监听器可能依赖于其他的服务或组件,这些依赖需要在监听器实例化之前解决。通过 BeanFactoryAbstractApplicationEventMulticaster 可以确保在调用监听器前,所有依赖都已正确注入。
  • 按需加载: 在某些情况下,监听器可能配置为懒加载,即只有在实际需要时才创建实例。AbstractApplicationEventMulticaster 通过 BeanFactory 可以按需创建和获取这些懒加载的监听器,从而优化资源使用和启动时间。

总结

通过实现 BeanFactoryAware 接口,AbstractApplicationEventMulticaster 获得了一个关键的能力:直接访问 Spring 的 BeanFactory,从而能够动态管理和调用应用中的所有事件监听器。这种设计大大增加了应用的灵活性和可扩展性,使得开发者可以更容易地添加和修改事件监听器,而不会影响到应用的其他部分。这对于维护大型、复杂的 Spring 应用来说是非常重要的。

优化性能

提前将类创建好,使用时直接调用以提高性能加快速度,这体现了什么设计模式或者设计思想呢?

by ChatGPT4

提前将类创建好,使用时直接调用以提高性能和加快速度的做法体现了对象池(Object Pool)模式的设计思想。此外,这种策略还涉及到懒加载(Lazy Initialization)预先初始化(Eager Initialization)的概念,这两者通常用来平衡启动性能与运行时性能。以下是这些设计模式或设计思想的详细介绍:

1. 对象池模式

对象池模式是一种创建对象并在池中保持它们的设计模式,目的是重用昂贵的对象来提高应用程序的性能和资源利用率。当系统需要一个对象时,它会从池中取出一个,使用后再放回池中而不是销毁。这种模式在需要频繁创建和销毁对象的情况下特别有用,比如数据库连接池。

在 Spring 框架中,单例模式的使用在某种程度上类似于对象池模式,因为每个单例 Bean 只被创建一次,并在整个容器中重用。

2. 懒加载

懒加载是指仅在首次需要时才创建对象的策略。这种方式可以延迟对象的创建成本,直到确实需要该对象时才发生,有助于减少应用程序启动时的初始化负载。Spring 允许 Bean 在被首次访问时才进行初始化,这通常通过设置 lazy-init="true" 来配置。

3. 预先初始化(预加载)

预先初始化或预加载是指在应用程序启动时提前创建并初始化对象,这有助于减少对象首次使用时的延迟。这在 Spring 中通过容器的启动过程中的 Bean 初始化阶段体现,其中所有非懒加载的单例 Bean 都会在应用程序上下文启动时创建和配置。

预先初始化可以减少运行时的延迟,因为所有必需的 Bean 在应用程序需要它们之前已经准备就绪,从而提高了响应性能。然而,这可能会增加应用程序启动时间。

总结

通过预先创建和初始化对象,Spring 通过减少每次对象请求的创建时间来优化性能。这种策略非常适合那些创建成本高但使用频率高的对象。结合懒加载,开发者可以根据具体的性能和资源利用需求灵活选择初始化策略。这两种策略的应用表明了 Spring 的设计非常注重提供灵活的性能优化工具,使得开发者可以根据应用的具体需要来调整其行为。

Spring-AOP

AOP动态代理,这种方式允许在不修改目标对象代码的情况下,动态地添加额外的行为(如日志、事务管理等),这是AOP编程范式的核心优势。

从以下几个角度讲起

  1. 动态代理-JDK
  2. 动态代理-CGLIB
  3. AOP代理工厂
  4. 常用Advice
  5. PointcutAdvisor: Pointcut和Advice的组合
  6. 动态代理融入生命周期
  7. 拦截器链

切点表达式

AspectJExpressionPointcut

1. 原语

原语(Primitives)通常指的是提供基本功能的最小构件。

在 AspectJ(一种面向切面的编程语言)中,切点原语(Pointcut Primitives)是构建切点表达式的基础元素,它们定义了何处和何时应用切面的规则。切点原语直接对应于程序执行的某些具体事件或动作,如方法调用 execution、方法执行 call等。

2. 常用对象

2.1 PointcutPrimitive

枚举类型,定义了不同的切点原语(切点的基本类型)

2.2 PointcutParser

解析切点表达式的解析器。它将字符串形式的切点表达式转换成 PointcutExpression 对象

2.3 PointcutExpression

这个类代表一个切点表达式,通常用于存储和管理切点表达式字符串

3. 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {
private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();
static {
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
}
private final PointcutExpression pointcutExpression;
/**
* 构造方法接收一个AspectJ表达式字符串作为参数。这个表达式用来定义何时触发切面。
* @param expression
*/
public AspectJExpressionPointcut(String expression) {
// 通过方法获取一个 PointcutParser 实例,这个解析器支持指定的原语和类加载器。
PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
// 使用上述解析器解析传入的AspectJ表达式,并将解析结果存储在 pointcutExpression 字段中
pointcutExpression = pointcutParser.parsePointcutExpression(expression);
}
// 类匹配器
@Override
public boolean matches(Class<?> clazz) {
return pointcutExpression.couldMatchJoinPointsInType(clazz);
}
// 方法匹配器
@Override
public boolean matches(Method method, Class<?> targetClass) {
return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
}
@Override
public ClassFilter getClassFilter() {
return this;
}
@Override
public MethodMatcher getMethodMatcher() {
return this;
}
}

动态代理-JDK

<span style="color:red">强调:JDK动态代理一切基于接口,原始类和代理类是基于同一个接口的不同子实现类,二者之间的转换要通过接口来实现,倘若二者直接相互转换,便会出现报错。

1. 简单示例

(简单了解JDK动态代理)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ProxyFactory {
private TrainStation station = new TrainStation();
public SellTickets getProxyObject(){
SellTickets proxyObject = (SellTickets) Proxy.newProxyInstance(
station.getClass().getClassLoader(),
station.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke方法执行了");
System.out.println("代售点收取一定的服务费用(jdk动态代理 )");
Object object = method.invoke(station, args);
return object;
}
}
);
return proxyObject;
}
}

1.1 缺点

耦合度太高

  • 目标对象耦合死了
  • 增强逻辑耦合死了
  • 逻辑都集中在一个方法中

2. AdvisedSupport

用来封装AOP需要的代理对象信息(目标对象、拦截器、方法匹配器)

AdvisedSupport

  • TargetSource
  • MethodInterceptor
  • MethodMatcher
1
2
3
4
5
6
7
8
9
10
11
// "被建议的支持",用来保存AOP相关的配置信息
// 当创建代理对象时,需要知道目标对象、拦截器、方法匹配器等信息,AdvisedSupport就是用来保存这些信息的
public class AdvisedSupport {
// 目标对象
private TargetSource targetSource;
// 拦截器,用于在目标方法调用前后增加额外的逻辑
private MethodInterceptor methodInterceptor;
// 方法匹配器,用于判断哪些方法需要被拦截和增强
private MethodMatcher methodMatcher;
// getter setter方法
}

3. ReflectiveMethodInvocation

ReflectiveMethodInvocation implements MethodInvocation

与Aware接口功能类似,使拦截器能够感知到目标对象、目标方法和方法参数等信息,在保证低耦合的同时还能在重写的invoke方法中调用外部信息,执行更多操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package org.springframework.aop.framework;

import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;

/**
* 反射 方法 调用
*/
public class ReflectiveMethodInvocation implements MethodInvocation {

/**
* 目标对象
*/
protected final Object target;

/**
* 要通过反射调用的具体方法
*/
protected final Method method;

/**
* 方法参数数组
*/
protected final Object[] arguments;

public ReflectiveMethodInvocation(Object target, Method method, Object[] arguments) {
this.target = target;
this.method = method;
this.arguments = arguments;
}

@Override
public Method getMethod() {
return method;
}

@Override
public Object[] getArguments() {
return arguments;
}

/**
* 执行原有方法
* @return
* @throws Throwable
*/
@Override
public Object proceed() throws Throwable {
return method.invoke(target, arguments);
}

@Override
public Object getThis() {
return target;
}

@Override
public AccessibleObject getStaticPart() {
return method;
}
}

4. JdkDynamicAopProxy

JdkDynamicAopProxy implements AopProxy, InvocationHandler

就是刚刚那段简易示例的Spring-AOP版,解决了高耦合的缺点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* JDK动态代理
* 两个接口:
* 1. AopProxy 提供代理对象方法
* 2. InvocationHandler,JDK动态代理技术的一部分,用于处理代理对象的方法调用
* 调用 处理程序
*/
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {

private final AdvisedSupport advised;

public JdkDynamicAopProxy(AdvisedSupport advised) {
this.advised = advised;
}

@Override
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(), advised.getTargetSource().getTargetClass(), this); // 第三个参数是InvocationHandler的子实现类,实现了invoke方法,在这里就是this即本类
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断是否对一个特定的方法调用应用拦截器,涉及了方法匹配逻辑(就是上面的切点表达式匹配方法)
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
// 如果匹配,则执行被增强对象的方法
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
}
// 如果不匹配,那就执行原有方法
return method.invoke(advised.getTargetSource().getTarget(), args);
}
}

5. InvocationHandler

java.lang.reflect包下的一个接口

InvocationHandler 就像是代理对象的 “管家”,当有人调用代理对象的方法时,实际上是由这个 “管家” 接收到了请求。这个 “管家” 的主要工作就是:

  • 接收代理对象的方法调用请求。
  • 根据请求的方法和参数,决定如何处理这个调用。
  • 最后,返回调用结果给调用者。

定义了一个方法 invoke(),当代理对象的方法被调用时,invoke() 方法会被调用,代理对象的方法调用会委托给 invoke() 方法来处理。

invoke() 方法中,有三个参数:

  • proxy:代理对象本身。
  • method:被调用的方法对象,是被代理对象的一个方法。
  • args:方法调用时传递的参数。

所以,InvocationHandler 就是一个用来处理代理对象方法调用的接口,它决定了代理对象的行为。

6. 执行流程

开发者实现 MethodInterceptor接口,重写 invoke方法自定义逻辑

1
2
3
4
5
6
7
8
9
public class WorldServiceInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
Object result = invocation.proceed();
System.out.println("after");
return null;
}
}

创建 AdvisedSupport对象,并为之赋值

1
2
3
4
5
6
7
8
9
10
11
12
private AdvisedSupport advisedSupport;
@Before
public void setup() {
WorldService worldService = new WorldServiceImpl();
advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(worldService);
WorldServiceInterceptor methodInterceptor = new WorldServiceInterceptor();
MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(* org.springframework.service.WorldService.explode(..))").getMethodMatcher();
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodInterceptor(methodInterceptor);
advisedSupport.setMethodMatcher(methodMatcher);
}

传递 adviseSupport参数,执行 getProxy方法

1
WorldService proxy = (WorldService) new JdkDynamicAopProxy(advisedSupport).getProxy();

getProxy内部调用 Proxy.newProxyInstance方法,创建代理对象

1
2
3
4
@Override
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(), advised.getTargetSource().getTargetClass(), this);
}

第三个参数为 InvocationHandler的子实现类,重写 InvocationHandlerinvoke方法

1
2
3
4
5
6
7
8
9
10
11
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断是否对一个特定的方法调用应用拦截器,涉及了方法匹配逻辑(就是上面的切点表达式匹配方法)
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
// 如果匹配,则执行被增强对象的方法
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
}
// 如果不匹配,那就执行原有方法
return method.invoke(advised.getTargetSource().getTarget(), args);
}

调用 advised.getMethodInterceptor方法得到用户自定义的拦截器对象

1
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();

调用自定义拦截器的 invoke方法(此处 invoke方法的返回值为增强方法的返回值),传递 ReflectiveMethodInvocation参数(使自定义拦截器能够感知目标对象、目标方法和方法参数等信息)。至此执行完成

1
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));

7. 部分原理分析

Proxy.newProxyInstance方法在内存中动态生成了一个代理对象

7.1 查看内存中动态代理对象

使用阿里巴巴开源的 Java 诊断工具(Arthas【阿尔萨斯】)查看代理类的结构

  1. 下载好jar包

  2. 打开终端,进入jar包所在目录

  3. 运行jar包

    1
    java -jar arthas-boot.jar
  4. 选择内存中的Java进程

    1
    2
    3
    4
    5
    [INFO] arthas-boot version: 3.1.1
    [INFO] Found existing java process, please choose one and hit RETURN.
    * [1]: 23712 org.jetbrains.jps.cmdline.Launcher
    [2]: 22388 com.intellij.rt.junit.JUnitStarter
    [3]: 20776
  5. 现在idea中得到代理类的全限定类名,不要让程序停止,否则会释放内存

    1
    System.out.println(proxyObject.getClass().toString());

    然后输入jar + 全限定类名

    1
    jad jdk.proxy2.$Proxy5
  6. 然后终端就会打印出该类的Java代码,完成了!

7.2 动态代理类分析

java.lang.reflect.Proxy类中,有 InvocationHandler成员变量

1
2
3
4
public class Proxy {
protected InvocationHandler h;
//...
}

只保留关键信息,动态代理类如下(重点全写注释上了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 继承了java.lang.reflect.Proxy类
public final class $Proxy5 extends Proxy implements WorldService {

private static final Method m3;

// 通过反射获取WorldService类的explode方法对象
static {
m3 = Class.forName("org.springframework.service.WorldService").getMethod("explode", new Class[0]);
}

// 构造方法,将实现了InvocationHandler的子实现类对象赋给父类的成员变量
public $Proxy5(InvocationHandler invocationHandler) {
super(invocationHandler);
}

// 通过invoke方法执行了InvocationHandler的子实现类对象(即真实的拦截器对象)中的拦截器中重写的方法
public final void explode() {
this.h.invoke(this, m3, null);
}
}

8. 还不会的地方

java.lang.reflect包下

  • Method.invoke底层原理(应该要学完JVM再看jdk源码)
  • Proxy底层原理(主要是用到了 newProxyInstance方法)

9. 设计模式

9.1 代理模式

9.2 感知设计模式

Aware和ReflectiveMethodInvocation

这类设计模式使得组件能够感知并操作其所处的上下文环境,从而提供更为灵活和动态的行为。

在某种程度上,ReflectiveMethodInvocation和 Spring 中的 Aware 接口确实有一些共通之处,因为它们都涉及到对象在运行时对外部资源的感知或依赖。让我们来分析一下它们之间的相似之处:

  1. 感知外部资源
    • Aware 接口:Spring 中的 Aware 接口(如 ApplicationContextAwareBeanFactoryAware)使 Bean 能够感知到容器的存在或者其他资源,比如获取应用程序上下文或者 Bean 工厂。
    • ReflectiveMethodInvocation:在这行代码中,ReflectiveMethodInvocation 对象被创建,并传递给 methodInterceptorinvoke() 方法。这个对象使拦截器能够感知到目标对象、目标方法和方法参数等信息。
  2. 依赖注入
    • Aware 接口:实现了 Aware 接口的类通常会通过依赖注入的方式获取所需的资源。
    • ReflectiveMethodInvocation:这行代码中的 ReflectiveMethodInvocation 对象通过构造函数的方式接收了目标对象、目标方法和方法参数等信息,这可以看作是一种依赖注入的方式。
  3. 解耦合
    • Aware 接口:通过 Aware 接口,Bean 与容器或其他资源之间的耦合度降低了,使得 Bean 更加灵活和可扩展。
    • ReflectiveMethodInvocation:这行代码中的 ReflectiveMethodInvocation 对象充当了方法调用的上下文,使得拦截器可以在方法调用时执行额外的逻辑,而不需要直接与目标对象进行交互,从而降低了拦截器与目标对象之间的耦合度。

虽然这两者在具体实现和应用场景上有所不同,但它们确实都涉及到了对象在运行时对外部资源的感知或依赖,以及为了解耦合而采用的设计思想。

动态代理-CGLIB

AOP代理工厂

判断是否使用cglib代理

1. JDK CGLIB 动态代理比较

面试题

都还学的不够深,jdk要看反射源码去,cglib要去看cglib源码

常用Advice

BeforeAdvice为例

1. 执行流程

(跟JDK动态代理执行流程差不多,中间有点不一样的地方)

开发者实现 MethodBeforeAdvice,重写 before()方法

1
2
3
4
5
6
public class WorldServiceBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] arg, Object target) throws Throwable {
System.out.println("BeforeAdvice: do something before the earth explodes");
}
}

关键类 MethodBeforeAdviceInterceptor 拦截器 聚合 MethodBeforeAdvice通知类,在 invoke()方法中调用通知类的 before()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// MethodBeforeAdviceInterceptor implements MethodInterceptor 拦截器
/**
* 用于在目标方法执行前拦截并执行相应的方法前通知
*/
public class MethodBeforeAdviceInterceptor implements MethodInterceptor {

private MethodBeforeAdvice advice;

// 聚合通知类,集成通知类的同时降低耦合度
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
this.advice = advice;
}

@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 在执行被清理方法之前,先执行before advice操作
// 给before传递参数,调用开发者的MethodBeforeAdvice子实现类中重写的invoke方法
this.advice.before(invocation.getMethod(), invocation.getArguments(), invocation.getThis());
// 返回的就是返回值,invoke调用的实际方法的返回值(原有对象或代理对象)
return invocation.proceed();
}
}

然后实现通知类,将通知类作为对象new前置方法拦截器,将拦截器赋给 advisedSupport

1
2
3
4
5
6
7
8
9
10
@Test
public void testBeforeAdvice() throws Exception {
// 设置BeforeAdvice
WorldServiceBeforeAdvice beforeAdvice = new WorldServiceBeforeAdvice();
MethodBeforeAdviceInterceptor methodBeforeAdviceInterceptor = new MethodBeforeAdviceInterceptor(beforeAdvice); // 把前置通知给了拦截器
// 它把@Before中设置的拦截器给覆盖了
advisedSupport.setMethodInterceptor(methodBeforeAdviceInterceptor);
WorldService proxy = (WorldService) new ProxyFactory(advisedSupport).getProxy();
proxy.explode();
}

就是拦截器那里跟JDK动态代理有点不一样,剩下完全一样,将拦截器插入动态代理的过程中

CGLIB动态代理也是一样

PointcutAdvisor: Pointcut和Advice的组合

Spring-AOP配置切面的另一种方式,通过 Advisor配置

正常来说

PointcutAdvisor是将 Pointcut切点表达式对象和 Advice通知类对象在内部组合起来,开发者只需要设置目标对象和 Advisor对象 (内部有通知类和切点表达式,通知类在底层会根据接口自动创建拦截器对象)便能完成AOP的配置。

但是,mini-spring没有实现这部分内容,所以拦截器对象要自己手动设置。

1. <aspect><advisor>的区别

代码上 使用上

<aspect>方式是直接根据 Aware接口获得的 BeanFactory对象来给 adviceSupport传递参数,更加灵活

<advisor>方式将 PointcutAdvice封装,只使用 AspectJExpressionPointcutAdvisor即可,底层通过得到通知类的接口来得到拦截器,对外的接口少,更简单

image-20240410213636349

动态代理融入bean生命周期

先分清aspect标签配置与advisor配置方式的区别

aspect就是什么都自己指定,自己执行通知类型是before还是after等等

advisor通知内部会通过接口的方式来确认通知的类型

所以advisor就可以说是上面的pointcut和advice的组合(待会儿再看看去)

1. 执行流程

xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8" ?>
<beans>

<bean id="worldService" class="org.springframework.service.WorldServiceImpl"/>

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<bean id="beforeAdvice" class="org.springframework.common.WorldServiceBeforeAdvice"/>

<bean id="pointcutAdvisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="expression" value="execution(* org.springframework.service.WorldService.explode(..))"/>
<property name="advice" ref="methodInterceptor"/>
</bean>

<bean id="methodInterceptor" class="org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
<property name="advice" ref="beforeAdvice"/>
</bean>
</beans>

解析配置文件,将以上bean全部注入Spring容器

1
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:auto-proxy.xml");

进入 getBean()方法执行流程

1
WorldService worldService = applicationContext.getBean("worldService", WorldService.class);

AbstractBeanFactory中的 getBean()方法,调用 AbstractAutowireCapableBeanFactorycreateBean()方法,传递 beanNamebeanDefinition参数(后面需要用它俩来生成)。

1
2
3
4
5
6
7
8
9
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
// 如果bean需要代理,调用resolveBeforeInstantiation(实例化之前解析)返回代理对象
Object bean = resolveBeforeInstantiation(beanName, beanDefinition);
if (bean != null) {
return bean;
}
return doCreateBean(beanName, beanDefinition);
}

调用 resolveBeforeInstantiation()方法获取实例化好的代理Bean

1
2
3
4
5
6
7
8
9
protected Object resolveBeforeInstantiation(String beanName, BeanDefinition beanDefinition) {
// 1. 首先,调用applyBeanPostProcessorsBeforeInstantiation方法尝试获取一个bean实例。
Object bean = applyBeanPostProcessorsBeforeInstantiation(beanDefinition.getBeanClass(), beanName);
// 2. 如果获取到了,那么会再调用applyBeanPostProcessorsAfterInitialization对这个bean实例进行后续处理
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
return bean;
}

调用 applyBeanPostProcessorsBeforeInstantiation方法,遍历已注册的 BeanPostProcessor,如果存在 BeanPostProcessor实现了 InstantiationAwareBeanPostProcessor接口,则说明该 BeanPostProcessor会内部实现了 postProcessBeforeInstantiation()方法,能够根据 beanClassbeanName生成增强后的代理对象,从而替代原来的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName) {
// 1. 获得所有实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor
for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
// 2. 获得每一个后处理器的postProcessBeforeInstantiation方法返回值
Object result = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessBeforeInstantiation(beanClass, beanName);
/* 3. 如果这个方法返回一个非null对象,表示通过代理或其他方式已经处理了bean的实例化,
因此不需要再进行标准的实例化过程。该对象会被直接返回并终止后续处理器的调用。*/
if (result != null) {
return result;
}
}
}
/* 4. 如果所有的InstantiationAwareBeanPostProcessor都没有提前实例化bean,
那么applyBeanPostProcessorsBeforeInstantiation方法将返回null,
表示标准实例化流程应继续进行。*/
return null;
}

也就是说 DefaultAdvisorAutoProxyCreator就相当于一个自动创建代理对象的 BeanPostProcessor,需要在配置文件中将其注入Spring容器。

1
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

DefaultAdvisorAutoProxyCreator实现 InstantiationAwareBeanPostProcessor接口和 BeanFactoryAware接口。

postProcessorBeforeInstantiation()方法实现逻辑,就是通过 Aware接口感知到的 BeanFactory来获取Spring容器中拦截器的各种信息,并由此创建出 advisedSupport,然后使用 ProxyFactory.getProxy()方法创建出对应的代理对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

private DefaultListableBeanFactory beanFactory;

/**
* 由于实现了BeanFactoryAware接口,此方法用于注入BeanFactory。
* DefaultListableBeanFactory使用BeanFactory来访问容器中的beans和其他配置
* @param beanFactory
* @throws BeansException
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (DefaultListableBeanFactory) beanFactory;
}

/**
* 在Bean实例化之前,检查是否有任何AspectJExpressionPointcutAdvisor适用于即将实例化的bean。
* 如果找到匹配的advisor的话,那就为bean创建一个代理
* @param beanClass
* @param beanName
* @return
* @throws BeansException
*/
@Override // 实例化
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
// 1. 检查传入的参数是否为基础设施类,避免死循环
if (isInfrastructureClass(beanClass)) {
return null;
}

// 2. 从BeanFactory中获取所有AspectJExpressionPointcutAdvisor,遍历它们来查找可以应用于当前 bean 类的 advisor。
Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
try {
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
ClassFilter classFilter = advisor.getPointcut().getClassFilter();
// 3. 如果找到匹配的 advisor,使用 ProxyFactory 创建一个代理对象,并立即返回这个代理对象,从而替代标准的 bean 实例化流程。
if (classFilter.matches(beanClass)) {
AdvisedSupport advisedSupport = new AdvisedSupport();

BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
Object bean = beanFactory.getInstantiationStrategy().instantiate(beanDefinition);
TargetSource targetSource = new TargetSource(bean);
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());

// 返回代理对象
return new ProxyFactory(advisedSupport).getProxy();
}
}
} catch (Exception ex) {
throw new BeansException("Error create proxy bean for: " + beanName, ex);
}
return null;
}

/**
* 辅助方法:检查传入的参数是否为基础设施类(例如 Advice、Pointcut 或 Advisor)
* <p>
* 避免代理这些类型的类,因为这可能导致循环依赖和配置错误。
* @param beanClass
* @return
*/
private boolean isInfrastructureClass(Class<?> beanClass) {
return Advice.class.isAssignableFrom(beanClass)
|| Pointcut.class.isAssignableFrom(beanClass)
|| Advisor.class.isAssignableFrom(beanClass);
}

/**
* 初始化前 Bean后处理器
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

/**
* 初始化后 Bean后处理器
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override // 初始化
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

通过之前的方法一层层将代理对象返回给 creatBean方法,然后被创建的对象在 AbstractBeanFactorygetBean()方法中调用的 getObjectForBeanInstance()方法存储进单例池中。

至此流程结束。(但还不完美,如下)

2. 缺陷

代码中

1
MethodBeforeAdviceInterceptor methodBeforeAdviceInterceptor = new MethodBeforeAdviceInterceptor(new WorldServiceBeforeAdvice());

手动将实现了前置通知接口的通知类当作参数赋给Spring内部的 MethodBeforeAdviceInterceptor类,而 advisor配置方式应当能够根据接口自动识别要创建的拦截器对象

xml文件中,与Spring官方配置的对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="UTF-8" ?>
<beans>

<!--用于自动生成代理类的一个对象-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<!--adviceSupport需要的三个参数:目标对象、拦截器对象、切点表达式-->

<!--1. 目标对象--><!--和Spring官方一样-->
<bean id="worldService" class="org.springframework.service.WorldServiceImpl"/>

<!--通知对象,拦截器成员变量--><!--和Spring官方一样-->
<bean id="beforeAdvice" class="org.springframework.common.WorldServiceBeforeAdvice"/>

<!--Spring官方直接将通知类和切点表达式赋给Advisor对象,由advice内部根据自定义通知类实现的接口来创建拦截器(切面)-->
<!--
<aop:config>
<aop:advisor advice-ref="worldServiceBeforeAdvice" pointcut="execution(* org.springframework.service.WorldService.explode(..))" />
</aop:config>
-->

<!--mini-spring是按以下做法做的-->
<!--2. 拦截器对象-->
<bean id="methodInterceptor" class="org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
<!--成员变量为通知对象-->
<property name="advice" ref="beforeAdvice"/>
</bean>

<!--Advisor对象-->
<bean id="pointcutAdvisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<!--3. 切点表达式对象-->
<property name="expression" value="execution(* org.springframework.service.WorldService.explode(..))"/>
<!--2. 拦截器对象-->
<property name="advice" ref="methodInterceptor"/>
</bean>


<!--Spring官方的第二种做法,根据切点表达式和通知类创建拦截器对象-->
<!--
AOP配置
<aop:config>
定义切面
<aop:aspect ref="methodInterceptor">
定义切点
<aop:pointcut id="explodePointcut" expression="execution(* org.springframework.service.WorldService.explode(..))"/>
应用前置通知
<aop:before method="beforeMethod" pointcut-ref="explodePointcut"/>
</aop:aspect>
</aop:config>
-->

</beans>

如果自己补全这一块儿的话:

xml部分,要自己设置一遍 aop-config对应的xml标签,然后自己封装并解析。

代码部分,要自己能根据自定义通知类实现的接口 实例化对应的拦截器对象并将其传递给 adviceSupport对象做参数。

有点内容呀,能实现,但是暂时来不及了,现在是4月27号,进度有点慢了,这块儿的存疑及解决方案写的挺清楚了,先了解就好,暂时的重点是过完mini-spring、spring-mvc、spring-boot源码,等这些弄完再回头看,<span style="color:red">插眼

注解

此处注解的底层实现并融入生命周期 全靠两个后处理器。

常见注解:Spring基础 - Spring 常用七大类注解 | 素文宅 (yoodb.com)

1
2
3
<!--xml文件解析器解析到包-->
<!--将该包下带了@Component注解的Bean都注入到Spring容器当中-->
<component-scan base-package="org.springframework.bean"/>
1
2
3
4
<!--将PropertyPlaceholderConfigurer注入Spring容器中,将properties文件作为参数传递进去-->
<bean class="org.springframework.beans.factory.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:car.properties" />
</bean>

分为三部分:注解替代bean注入,注解替代bean的属性property注入,xml和@Value注解占位符的解析

1._包扫描、@Component注解识别,注入beanDefinition,注册AutowiredAnnotationBeanPostProcessor

XmlBeanDefinitionReaderxml解析器类中添加对 component-scanbase-package的解析,接收到 base-package字符串信息。调用 doScan()方法,该方法内部就完成了 beanDefinition的注册等操作。

在xml解析器中调用 ClassPathBeanDefinitionScannerdoScan()方法,使用注解的方式完全替代了xml解析的方式,除了包扫描还需要xml文件来触发。

该部分先扫描包路径下所有标记了 @Component注解的类,并将其封装为 BeanDefinition对象。然后针对每一个 BeanDefinition设置作用域、确定名称、并注册 AutowiredAnnotationBeanPostProcessorBeanDefinition用于后续的属性注入。

主要涉及 XmlBeanDefinitionReader,ClassPathBeanDefinitionScanner,ClassPathScanningCandidateComponentProvider,详见代码。

2._实例化bean,@Value注解扫描,为bean注入属性

AutowiredAnnotationBeanPostProcessor在上面被实例化为 BeanDefinition并注册进 BeanDefinition容器,后续 refresh()方法才能通过 beanFactory.preInstantiateSingletons()提前实例化Bean方法调用并执行后处理器方法,从而做到自动执行。

执行流程

实例化Bean

1
2
3
4
5
6
7
8
// AbstractApplicationContext
@Override
public void refresh() throws BeansException {
// ...
// 5. 提前实例化单例Bean,提高应用程序的启动性能和响应速度
beanFactory.preInstantiateSingletons();
// ...
}

内部调用 AbstractAutowireCapableBeanFactorydoCreateBean方法中的 applyBeanPostprocessorsBeforeApplyingPropertyValues方法,触发 AutowiredAnnotationBeanPostProcessorbean后处理器的执行,返回被属性注入、占位符被替换为真实值的完整的Bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// AbstractAutowireCapableBeanFactory
protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition);
//在设置bean属性之前,允许BeanPostProcessor修改属性值
applyBeanPostprocessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
//为bean填充属性
applyPropertyValues(beanName, bean, beanDefinition);
//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法
initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
//注册有销毁方法的bean
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
if (beanDefinition.isSingleton()) {
addSingleton(beanName, bean);
}
return bean;
}
// 修改Bean
protected void applyBeanPostprocessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
PropertyValues pvs = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessPropertyValues(beanDefinition.getPropertyValues(), bean, beanName);
if (pvs != null) {
for (PropertyValue propertyValue : pvs.getPropertyValues()) {
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
}
}
}
}

通过该接口识别指定解析注解的后处理器

1
2
3
4
5
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
// ...
// bean实例化之后,设置属性之前执行,用于修改属性值(将占位符修改为真实值)
PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException;
}

AutowiredAnnotationBeanPostProcessor postProcessPropertyValues方法的内部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* <p>一个 Bean 后处理器,主要负责处理带有 @Autowired@Value 注解的属性的依赖注入。</p>
* <p>这个类实现了 InstantiationAwareBeanPostProcessor 接口,这意味着它在 Spring 容器实例化 bean 之后,在调用 bean 的初始化方法之前和之后都会执行相应的逻辑。它还实现了 BeanFactoryAware 接口,用于在运行时获取 BeanFactory,这样可以在需要时从容器中获取其他 bean。</p>
* <p>在 postProcessPropertyValues 方法中,它首先检查 bean 中的每个字段是否带有 @Value 注解,如果有,则解析注解中的值并进行注入。然后它再次遍历字段,检查是否带有 @Autowired 注解,如果有,则根据字段类型获取相应的依赖 bean,并进行注入。</p>
* <p>总的来说,AutowiredAnnotationBeanPostProcessor 的作用是完成对带有 @Autowired@Value 注解的属性进行自动依赖注入的操作。</p>
*/
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

private ConfigurableListableBeanFactory beanFactory;

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
// 完成依赖注入操作
@Override
public MutablePropertyValues postProcessPropertyValues(MutablePropertyValues pvs, Object bean, String beanName) throws Exception {
// 获取Bean的Class对象和该类中所有声明的字段fields
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();

// 处理@Value注解

// 1. 遍历字段
for (Field field : fields) {
// 2. 检查当前字段是否带有@Value注解
Value valueAnnotation = field.getAnnotation(Value.class);
if (valueAnnotation != null) {
// 3. 如果字段带有@Value注解,获取value属性,这是要注入到字段中的值
String value = valueAnnotation.value();
// 4. 使用beanFactory的resolveEmbeddedValue方法来解析字符串中的占位符,获得实际的属性值
value = beanFactory.resolveEmbeddedValue(value);
/* 5. 工具类
接收三个参数:
bean:要设置值的Bean对象
fieldName:Bean对象中字段的名称
value:要设置到字段中的值
通过反射机制获取Bean对象中指定字段的Field对象
然后调用set方法设置字段的值
最后返回设置后的Bean对象

总的来说,就是将解析后的值(value)注入到指定 Bean(bean)的指定字段(field.getName())中
*/
BeanUtil.setFieldValue(bean, field.getName(), value);
}
}

// 处理@Autowire注解

// 1. 遍历字段
for (Field field : fields) {
// 2. 检查当前字段是否带有@Autowired注解
Autowired autowiredAnnotation = field.getAnnotation(Autowired.class);
if (autowiredAnnotation != null) {
// 3. 如果带有@Autowired注解,接着获取字段的类型fieldType
Class<?> fieldType = field.getType();
// 4. 该变量用于存储依赖Bean的名称
String dependentBeanName = null;
// 5. 获取字段上的@Qualifier注解
Qualifier qualifierAnnotation = field.getAnnotation(Qualifier.class);
Object dependentBean = null;
// 6.1 如果存在@Qualifier注解的话,说明开发者指定了一个特定的Bean名称来注入
if (qualifierAnnotation != null) {
// 将@Qualifier注解的值赋给dependentBeanName
dependentBeanName = qualifierAnnotation.value();
// 使用getBean(dependentBeanName, fieldType)方式获取特定Bean实例
dependentBean = beanFactory.getBean(dependentBeanName, fieldType);
} else {
// 6.2 如果不存在,使用getBean(fieldType)方式获取Bean实例
dependentBean = beanFactory.getBean(fieldType);
}
// 7 将解析后的值注入到指定字段中
BeanUtil.setFieldValue(bean, field.getName(), dependentBean);
}
}

// 返回处理后的MutablePropertyValues对象,该对象包含了所有属性值的设置
return pvs;
}
// ...
}

添加@Autowired操作逻辑

一、BeanFactory接口,DefaultListableBeanFactory类,AbstractApplicationContext抽象类,多实现了一个 getBeanOfType()的方法,根据类型获取Bean。、

二、@Autowired注解、@Qualifier注解用于实现依赖注入

  • @Autowired注解:可以用于类的成员变量、构造函数、设置方法上,用于自动注入依赖。当Spring容器启动时,它会自动查找相应的Bean,并注入到标注了 @Autowired的字段或方法中。默认情况下,Spring按照类型(Type)进行匹配,找到合适的Bean进行注入。
  • @Qualifier注解:当Spring上下文中存在多个相同类型的Bean时,使用 @Autowired进行注入可能会出现无法确定注入哪一个Bean的情况。此时可以使用 @Qualifier注解来指定注入哪一个Bean。@Qualifier需要与 @Autowired一起使用,用于指定Bean的名称。

例如:

1
2
3
@Autowired
@Qualifier("userServiceImp")
private UserService userService;
1
2
3
4
@Autowired
public void setUserService(@Qualifier("userServiceImpl") UserService userService) {
this.userService = userService;
}

三、AutowiredAnnotationBeanPostProcessor类中加入对这两个注解解析的逻辑(见上面的代码)

3._占位符解析

主要分为两部分

3.1 解析xml文件中的占位符

refresh()方法中自动执行 BeanFactoryPostProcessor子实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {
// 前缀
// 后缀
private String location;
public void setLocation(String location) {this.location = location;}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 加载Property文件
Properties properties = loadProperties();
// 解析xml文件中的占位符
processProperties(beanFactory, properties);
// 解析@Value注解中的占位符,将其加到BeanFactory的解析器集合中
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(properties);
beanFactory.addEmbeddedValueResolver(valueResolver);
}
// ...
private class PlaceholderResolvingStringValueResolver implements StringValueResolver {
private final Properties properties;
public PlaceholderResolvingStringValueResolver(Properties properties) {
this.properties = properties;
}
public String resolveStringValue(String strVal) throws BeansException {
return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties);
}
}
}

3.2 解析@Value注解中的占位符

注意,refresh()方法中,BeanFactoryPostProcessor是自动执行的,BeanPostProcessor是在实例化Bean时在 getBean()方法的 doCreateBean()方法中自动执行的

基于第二部分,中间穿插了一个解析嵌入值的方法

执行流程

1
2
3
// AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware
// @Override postProcessPropertyValues
value = beanFactory.resolveEmbeddedValue(value);
1
2
3
4
5
6
7
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
// ...
// 添加嵌入值解析器
void addEmbeddedValueResolver(StringValueResolver valueResolver);
// 解析嵌入值
String resolveEmbeddedValue(String value);
}

遍历嵌入值解析器,调用解析方法 resolveStringValue

1
2
3
4
5
6
7
8
9
10
11
12
13
// AbstractBeanFactory
// 存储解析器的容器
private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<StringValueResolver>();
public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
this.embeddedValueResolvers.add(valueResolver);
}
public String resolveEmbeddedValue(String value) {
String result = value;
for (StringValueResolver resolver : this.embeddedValueResolvers) {
result = resolver.resolveStringValue(result);
}
return result;
}
1
2
3
public interface StringValueResolver {
String resolveStringValue(String strVal);
}

然后 resolveStringValue()方法就调用到了 PropertyPlaceholderConfigurer中对占位符的处理

3.3_适配器模式

通过内部类的方式将两个不同的接口的子实现类结合到了一起。

PlaceholderResolvingStringValueResolverPropertyPlaceholderConfigurer的内部类,实现了额外的标记接口,调用外部类中的方法作为自己内部对接口的重写方法。

fix

第一次提交改动了一个东西

DefaultAdvisorAutoProxyCreatorAbstractAutowireCapableBeanFactory

以前是直接在 creatBean()方法中单开了一条逻辑处理动态代理,没有注入属性那一步操作。

现在是将对动态代理的操作插入到了 initializeBean()方法的 BeanPostProcessor的前置和后置处理中,每一个后处理器都会被应用到每一个bean上,即每个bean都会进入动态代理的判断,判断该bean是否符合切点表达式,如果符合,则返回代理对象,如果不符合,则返回原对象。通过 BeanPostProcessor真正融入生命周期。

随后进一步完善了Bean的生命周期,增加了前置处理和后置处理的操作

image-20240506171655743

1. 生命周期

Bean的生命周期是一个从创建到销毁的过程,此类中定义的Bean的生命周期如下:

  1. 前置处理(Pre-Instantiation)
    在Bean实际被创建之前,resolveBeforeInstantiation方法允许应用 BeanPostProcessors进行预处理,这可能会返回一个完全不同的对象。如果这个方法返回一个代理或增强过的对象,那么后续的标准实例化过程可能会被跳过。

  2. 实例化(Instantiation)
    首先,Spring容器通过 BeanDefinition(包含类的全名、作用域信息、属性描述等)来创建Bean的实例。实例化的方式可能通过构造器实例化、工厂方法实例化或其他方式。在 AbstractAutowireCapableBeanFactory中,实例化策略由 instantiationStrategy决定,并通过 createBeanInstance方法具体执行。

  3. 后置处理(Post-Instantiation)
    通过 applyBeanPostProcessorsAfterInstantiation方法可以进行一些后处理。如果此步骤中任何处理器返回false,将不会继续后续的属性填充。

  4. 修改属性值

    例如将占位符修改为真实值

  5. 属性填充(Populate Properties)
    如果 postProcessAfterInstantiation方法返回 true(默认行为),Spring将继续进行属性注入。这包括通过反射技术设置Bean的属性值。applyPropertyValues方法会将 BeanDefinition中定义的属性值应用到新创建的对象上。

  6. 初始化(Initialization)
    初始化是一个多步骤的过程,包括: a.调用 BeanPostProcessors的前置方法。 b.如果Bean实现了 InitializingBean接口,则调用其 afterPropertiesSet方法。 c.如果在 BeanDefinition中指定了自定义的初始化方法,该方法也将被调用。 d.调用 BeanPostProcessors的后置方法。

  7. 使用(Usage)
    这时,Bean已完全准备好,可以被应用程序使用。在这个阶段,Bean处于完全激活状态,可以响应对其方法的调用。

  8. 销毁(Destruction)
    对于单例作用域的Bean,当Spring容器关闭时,容器将调用注册的 DisposableBeandestroy方法以及自定义的销毁方法。这是清理资源和执行必要的清除任务的好机会。

在整个生命周期中,Spring通过使用多种钩子和操作提供了极大的灵活性,使得可以在创建和管理Bean时插入自定义逻辑和处理流程。AbstractAutowireCapableBeanFactory是实现这一生命周期复杂管理的核心组件之一,它通过多个扩展点允许开发者定制和优化Bean的行为和生命周期。

2. 前置处理

前置处理指的是在Bean实例化之前的处理。在这个阶段,可以通过Bean的后置处理器(BeanPostProcessor)的 postProcessBeforeInstantiation方法来进行操作。这个方法允许开发者在Bean的实际实例化之前修改Bean的定义或提供代理实现。这个处理阶段的主要作用和优势包括:

  • 修改或替换Bean定义
    • 开发者可以在Bean实例化前修改Bean的定义或配置,如改变Bean的作用域、调整Bean的属性等。
    • 可以完全替换掉原来的Bean定义,返回一个全新的代理或其他对象实例,从而影响Spring容器最终所创建的Bean对象。
  • 提前介入Bean的创建过程
    • 允许开发者在Bean的任何属性被设置前介入,提供一种方式来执行一些预处理操作,比如检查或准备一些必要的资源或条件。
    • 可以用于实现一些基于条件的逻辑,例如根据特定的配置信息或环境变量决定是否或如何创建某个Bean。
  • 提供代理实现
    • 常用于AOP(面向切面编程)中,允许在Bean实际创建之前插入代理,从而为Bean提供额外的功能,如安全检查、事务管理、日志记录等。
    • 这种代理实现通常涉及创建一个实现了原Bean接口的代理类,这个代理类在调用原始Bean的方法前后可以执行额外的操作。
  • 优化性能
    • 通过提前处理或替换Bean,可以避免不必要的Bean实例化,特别是在Bean的创建成本很高或者需要根据条件判断后才决定创建的情况下。
    • 这可以显著提高应用启动和运行的效率,尤其是在大型或复杂的Spring应用中。
  • 灵活性和可扩展性
    • 提供了一种机制,通过它开发者可以根据需要灵活地控制和扩展Bean的创建过程,使得应用能够更好地适应不断变化的需求和环境。

简单示例:

1
2
3
4
5
6
7
8
9
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("someBean")) {
// 修改Bean定义或返回代理对象
}
return null; // 返回null,容器会继续使用默认的实例化策略,返回bean,则跳过后面的所有生命周期
}
}

3. 后置处理

后置处理指的是在Bean实例化之后的处理。这个阶段也是通过实现BeanPostProcessor接口来进行,具体是通过 postProcessAfterInstantiation方法。在这个方法中,可以对Bean实例进行额外的配置或初始化。这个方法在Bean的属性被设置之后调用,可以用来进行一些依赖注入之外的自定义初始化逻辑。这个阶段的主要作用和优点包括:

  • 自定义修改或检查Bean实例
    • 在Bean属性设置之前,可以检查或修改Bean实例。这允许开发者对Bean实例执行一些状态或数据的验证,确保Bean在属性设置前已经满足某些条件。
    • 可以用来设置一些不通过Spring配置注入的属性或依赖。
  • 条件阻止属性注入
    • 通过返回值可以控制是否允许Spring继续对Bean进行属性注入。如果 postProcessAfterInstantiation方法返回 false,则Spring容器将不会对该Bean进行后续的属性设置操作,这可以用于条件化地阻止自动装配。
  • 增强Bean的功能
    • 可以在Bean完全配置前增加一些功能,比如对Bean实现一些自动化的配置检测或初始化一些在构造函数中无法完成的复杂成员。
  • 保证Bean的完整性和一致性
    • 在Bean的属性被注入前进行操作,可以确保当Bean的属性被注入时,Bean处于一个预期的状态,这对于保证Bean的一致性和完整性至关重要。

简单示例:

1
2
3
4
5
6
7
8
9
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (bean instanceof SomeClass) {
// 进行一些初始化操作
}
return true; // 返回true表示容器应继续正常处理,返回false表示阻止属性赋值
}
}

类型转换

1. 基础类关系

ConversionService接口,顶层接口,定义转换方法和是否能转换方法

Converter接口,一对一转换器接口,用于开发者自己实现

ConverterFactory接口,一对多转换器接口,开发者自己实现

GenericConverter接口,通用类型转换器接口

ConverterAdapter内部类 implements GenericConverter,聚合了 Converter

ConverterFactoryAdapter内部类 implements GenericConverter,聚合了 ConverterFactory

ConverterRedistry接口,注册接口,定义了写向转换器注册表中添加类型转换器的三个模板方法

GenericConverterService类 implements ConversionService,ConverterRedistry,类型转换中心,用于管理和执行从一个数据类型到另一个数据类型的转换

StringToNumberConverterFactory类,Spring内嵌的一个 ConverterFactory子实现类

DefaultConversionService类,预定义了一个转换器 StringToNumberConverterFactory,通过默认转换器来简化常见的数据转换任务,允许开发者轻松扩展或定制转换逻辑,以适应不同的应用场景,提高了开发效率和代码的可维护性。

2. 设计模式

2.1_适配器模式

  • 使用场景: 用于将一个类的接口转换成客户期望的另一个接口。ConverterConverterFactory通过 ConverterAdapterConverterFactoryAdapter被适配为 GenericConverter,从而可以统一处理。
  • 角色分配:
    • ConverterConverterFactory: 这些接口定义了简单的转换逻辑和基于类型的工厂转换逻辑。
    • ConverterAdapterConverterFactoryAdapter: 作为适配器,它们实现了 GenericConverter接口,允许 ConverterConverterFactoryGenericConversionService中统一管理。

2.2 策略模式

  • 使用场景: 策略模式用于定义一系列的算法,把它们一个个封装起来,并使它们可相互替换。此模式让算法的变化独立于使用算法的客户。
  • 角色分配:
    • GenericConverter: 充当具体策略角色,定义了不同的类型转换逻辑。
    • GenericConversionService: 充当上下文角色,使用不同的 GenericConverter策略来完成类型转换的任务。

2.3 其他

工厂模式、单例模式、模板方法模式这些就不多说了

3. 执行流程

BeanFactory接口

ConfigurableBeanFactory接口

AbstractBeanFactory抽象类

AbstractAutowireCapableBeanFactory抽象类

如何嵌入Bean的生命周期?

主要可以分为四部分:

  • 转换器和类型转换中心本身
  • 注入
  • 设置
  • 使用

xml文件

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!--主要是注入这个,剩下是自定义-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters" ref="converters"/>
</bean>
<bean id="car" class="org.springframework.bean.Car">
<property name="price" value="1000000"/>
<property name="produceDate" value="2021-01-01"/>
</bean>
<bean id="converters" class="org.springframework.common.ConvertersFactoryBean"/>
</beans>

3.1 转换器和类型转换中心本身

GenericConversionService类型转换中心使用适配器模式整合两种不同的转换器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
public class GenericConversionService implements ConversionService, ConverterRegistry {
/**
* <p>转换器映射表
* <p>键:GenericConverter.ConvertiblePair 类型,表示可转换的源类型与目标类型的组合
* <p>值:GenericConverter 类型,表示对应的类型转换器
*/
private Map<GenericConverter.ConvertiblePair, GenericConverter> converters = new HashMap<>();

// 检查是否存在源类型到目标类型的转换器
@Override
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
GenericConverter converter = getConverter(sourceType, targetType);
return converter != null;
}

// 执行类型转换
@Override
public <T> T convert(Object source, Class<T> targetType) {
// 确定源对象的类类型
Class<?> sourceType = source.getClass();
// 将基本数据类型转换为其对应的包装类类型
targetType = (Class<T>) BasicType.wrap(targetType);
// 找到合适的转换器
GenericConverter converter = getConverter(sourceType, targetType);
// 调用其convert方法转换对象
return (T) converter.convert(source, sourceType, targetType);
}

// ---三个添加转换器的方法
/**
* 添加一个简单的转换器
* @param converter 一个实现了 Converter 接口的类型转换器实例,用于执行单个类型到类型的转换
*/
@Override
public void addConverter(Converter<?, ?> converter) {
// 通过getRequiredTypeInfo方法获取转换器的源类型和目标类型信息
GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converter);
// 创建一个ConverterAdapter实例并注册到转换器映射中
ConverterAdapter converterAdapter = new ConverterAdapter(typeInfo, converter);
for (GenericConverter.ConvertiblePair convertibleType : converterAdapter.getConvertibleTypes()) {
converters.put(convertibleType, converterAdapter);
}
}
/**
* 添加一个转换器工厂
* @param converterFactory 一个实现了 ConverterFactory 接口的类型转换器工厂实例,用于动态获取类型到类型的转换器
*/
@Override
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converterFactory);
ConverterFactoryAdapter converterFactoryAdapter = new ConverterFactoryAdapter(typeInfo, converterFactory);
for (GenericConverter.ConvertiblePair convertibleType : converterFactoryAdapter.getConvertibleTypes()) {
converters.put(convertibleType, converterFactoryAdapter);
}
}
/**
* 通用类型转换器
* 重载的addConverter方法直接添加一个GenericConverter到映射中,这种转换器可以处理多种类型的转换
* @param converter 一个实现了 GenericConverter 接口的通用类型转换器实例,用于执行复杂的、特定场景下的类型转换
*/
@Override
public void addConverter(GenericConverter converter) {
for (GenericConverter.ConvertiblePair convertibleType : converter.getConvertibleTypes()) {
converters.put(convertibleType, converter);
}
}

// --- 用大量的反射,以获取GenericConverter.ConvertiblePair作为Map的键
// 通过反射获取对象实现的泛型接口的实际类型参数,以确定源类型和目标类型
private GenericConverter.ConvertiblePair getRequiredTypeInfo(Object object) {
//...
}
// 保护方法
protected GenericConverter getConverter(Class<?> sourceType, Class<?> targetType) {
//...
}
// 返回给定类的类层次结构列表,包括它的所有超类。
private List<Class<?>> getClassHierarchy(Class<?> clazz) {
//...
}

/**
* 适配Converter实例,使其可以注册到通用的类型转换服务中
*/
private final class ConverterAdapter implements GenericConverter {

private final ConvertiblePair typeInfo;

private final Converter<Object, Object> converter;

public ConverterAdapter(ConvertiblePair typeInfo, Converter<?, ?> converter) {
this.typeInfo = typeInfo;
this.converter = (Converter<Object, Object>) converter;
}

@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(typeInfo);
}

@Override
public Object convert(Object source, Class sourceType, Class targetType) {
return converter.convert(source);
}
}

/**
* 适配ConverterFactory实例,使其可以注册到通用的类型转换服务中
*/
private final class ConverterFactoryAdapter implements GenericConverter {

private final ConvertiblePair typeInfo;

private final ConverterFactory<Object, Object> converterFactory;

public ConverterFactoryAdapter(ConvertiblePair typeInfo, ConverterFactory<?, ?> converterFactory) {
this.typeInfo = typeInfo;
this.converterFactory = (ConverterFactory<Object, Object>) converterFactory;
}

@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(typeInfo);
}

@Override
public Object convert(Object source, Class sourceType, Class targetType) {
return converterFactory.getConverter(targetType).convert(source);
}
}
}

<span style="color:red">ConversionService是类型转换体系的核心接口,通过内部类适配器模式将以上三种类型转换器整合到一起,GenericConversionService是其实现类,DefaultConversionService在GenericConversionService的基础上添加内置转换器。

3.2 注入类型转换中心

首先,ConversionServiceFactoryBean有两个成员变量,其中一个是 GenericConversionService类型转换中心,ConversionServiceFactoryBean将所有的转换器都注册进类型转换中心当中,然后将类型转换中心作为bean注入到Spring容器当中。<span style="color:red">FactoryBean工厂注入方式 发挥了大作用,工厂方式允许在创建 Bean 实例时进行更复杂的逻辑处理,例如这里就通过该方式为Spring的GenericConversionService类型转换中心注入多个类型转换器,从而提供更大的灵活性和定制性

3.3 设置类型转换中心

AbstractApplicationContextfinishBeanFactoryInitialization()方法中,给 AbstractBeanFactory设置类型转换中心作为成员变量:先根据 getBean()方法获取到类型转换中心,然后调用 beanFactory.setConversionService()方法类型转换中心设置上去。

1
2
3
4
5
6
7
8
9
10
11
12
// AbstractApplicationContext#refresh()
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//设置类型转换中心
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);
if (conversionService instanceof ConversionService) {
beanFactory.setConversionService((ConversionService) conversionService);
}
}
//提前实例化单例bean
beanFactory.preInstantiateSingletons();
}

3.4 使用类型转换中心中的转换器

然后就是使用类型转换中心的转换器了

类型转换的时机有两个:

  • 为bean填充属性时,见AbstractAutowireCapableBeanFactory#applyPropertyValues
  • 处理@Value注解时,见AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues

以第一个为例,AbstractAutowireCapableBeanFactory#doCreaateBean()方法中在为Bean填充属性时,执行类型转换操作,注解和这个差不多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// applyPropertyValues
// 如果不是,则检查是否需要进行类型转换
// 获取value的实际类型
Class<?> sourceType = value.getClass();
// 获取目标bean对应的类型,自动找出对应bean类中该成员变量的类型,设为目标类型,然后进行转换操作
Class<?> targetType = (Class<?>) TypeUtil.getFieldType(bean.getClass(), name);
// 获取类型转换服务
ConversionService conversionService = getConversionService();
// 检查是否可以从sourceType转换到targetType
if (conversionService != null) {
if (conversionService.canConvert(sourceType, targetType)) {
// 如果可以,执行转换
value = conversionService.convert(value, targetType);
}
}

3.5 开发者使用

一种是使用Spring默认的,见3.4

另一种就是开发者自定义了,这里举个字符串和日期类型的例子

1
2
3
4
5
6
7
8
9
10
public class StringToLocalDateConverter implements Converter<String, LocalDate> {
private final DateTimeFormatter DATE_TIME_FORMATTER;
public StringToLocalDateConverter(String pattern) {
DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(pattern);
}
@Override
public LocalDate convert(String source) {
return LocalDate.parse(source, DATE_TIME_FORMATTER);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ConvertersFactoryBean implements FactoryBean<Set<?>> {
/**
* 创建并返回转换器集合
*/
@Override
public Set<?> getObject() throws Exception {
HashSet<Object> converters = new HashSet<>();
StringToLocalDateConverter stringToLocalDateConverter = new StringToLocalDateConverter("yyyy-MM-dd");
converters.add(stringToLocalDateConverter);
return converters;
}
@Override
public boolean isSingleton() {
return true;
}
}
1
2
3
4
5
6
7
@Test
public void testConversionService() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:type-conversion-second-part.xml");
Car car = applicationContext.getBean("car", Car.class);
assertThat(car.getPrice()).isEqualTo(1000000);
assertThat(car.getProduceDate()).isEqualTo(LocalDate.of(2021, 1, 1));
}

4. 总结

4.1 收获

  • 对适配器模式、策略模式的应用
  • FactoryBean的使用

4.2 应用场景

  • 前端向后端传递的通常是json格式字符串,需要类型转换

  • 后端开发者的自定义类型转换器

    • 自定义数据类型

      当你的应用需要处理特定业务逻辑的自定义数据类型时,如货币、复杂的时间周期、或是特殊的业务标识符等,标准的类型转换器可能不会提供这些类型的转换支持。在这种情况下,开发者需要实现并注册自定义转换器来确保数据可以正确地从一种格式转换为另一种格式。

    • 第三方类库模型

      如果你的应用集成了第三方服务或类库,这些外部系统可能使用不同的数据类型或格式。例如,如果一个外部库返回的日期格式是字符串,而你希望在你的系统中使用 java.time.LocalDate,你可能需要创建一个转换器来处理这种转换。

    • 数据库枚举类型处理

4.3 注意

“类型转换实际开发中开发者手动转换可能用不到,因为后端向前端传递数据传的就是字符串,没必要再转换。”这种想法不可以有!

显式进行转换可以提供更好的控制、一致性和灵活性!不然当你要对 getBean()到的数据做额外处理时,还得再次手动转换,做不到一致性。

循环依赖

<span style="color:blue">注意:在设计层面上,循环依赖通常是不良设计的标志。可以通过重新设计类的职责、引入中介者模式、使用事件驱动方法或将共同功能抽象到另一个类中来解决循环依赖问题。

循环依赖发生在两个或多个 Bean 互相依赖,形成一个循环链,导致 Bean 无法正常初始化。例如:

  • Bean A 依赖于 Bean B
  • Bean B 又依赖于 Bean A

Spring使用三级缓存来处理循环依赖,一般二级缓存就够处理循环依赖了,但是面对代理对象,二级缓存中存储的是实例化bean,实际需要的bean是代理bean。三级缓存就是为了解决代理对象的循环依赖问题。

1. 解决循环依赖的前置条件

  • Bean 必须是单例范围(singleton)。
  • 依赖注入的方式不能全是构造器注入的方式

2. 用到的类

一、

InstantiationAwareBeanPostProcessor接口(创建代理类的类实现的接口),多了个 getEarlyBeanReference()方法,用于提前暴露bean。

DefaultAdvisorAutoProxyCreator类(创建代理类的类),实现了上面那个方法,

该类还是创建代理对象的类,只是多了一个关于处理提前创建好的代理对象的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware

// 用于存储被提前创建的代理对象
private Set<Object> earlyProxyReferences = new HashSet<>();

// 这一步是正常流程执行AOP动态代理
// 初始化后置处理(Spring中,AOP代理在生命周期的最后阶段执行)
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (!earlyProxyReferences.contains(beanName)) {
return wrapIfNecessary(bean, beanName);
}
return bean;
}

// 这一步是提前创建代理对象
// 得到早期曝光对象
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
earlyProxyReferences.add(beanName);
return wrapIfNecessary(bean, beanName);
}

// 创建代理对象(wrap:包裹,计算机中指在原始对象的基础上创建一个代理对象)
protected Object wrapIfNecessary(Object bean, String beanName) {
// 内部执行创建代理对象的逻辑
}

二、

ObjectFactory接口,getObject()方法

唯一一个实现在 addSinglletonFactory()方法中做参数

三、

单例池(一级缓存)

早期曝光对象(二级缓存)

早期曝光对象工厂(三级缓存)

DefaultSingletonBeanRegistry类(默认单例注册表,bean容器及对其的基本操作都在这里)

getSingleton()方法:

  1. 尝试获取完全初始化的 Bean: 在获取 Bean 的时候,首先会从一级缓存中 singletonObjects 获取。如果有完全初始化的 Bean,则直接返回。
  2. 尝试获取早期引用的 Bean: 如果一级缓存中没有,则从二级缓存 earlySingletonObjects 获取。如果存在早期引用,则直接返回。
  3. 从三级缓存创建早期引用: 如果二级缓存也没有,Spring 会从三级缓存 singletonFactories 获取对象工厂 ObjectFactory,通过它来创建早期引用,然后将创建的早期引用放入二级缓存 earlySingletonObjects,并移除三级缓存中的工厂。
  4. 创建 Bean: 如果以上都没有找到 Bean,Spring 会尝试实例化该 Bean,在实例化的过程中可能会递归地调用其他 Bean。如果过程中遇到了循环依赖的问题,则使用二级缓存 earlySingletonObjects 中的早期引用来解决。
  5. 后处理器和代理: 如果 Bean 实例化过程中使用了 Bean 后处理器,处理器可能会将 Bean 转换成代理对象。代理对象通常会放入三级缓存,以在循环依赖情况下获取代理对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// DefaultSingletonBeanRegistry 默认单例注册表

// 单例池(一级缓存)
private Map<String, Object> singletonObjects = new HashMap<>();

// 早期曝光对象(二级缓存)
protected Map<String, Object> earlySingletonObjects = new HashMap<>();

// 早期曝光对象工厂(三级缓存)
private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

@Override
public Object getSingleton(String beanName) {
Object singletonObject = singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 从三级缓存放进二级缓存
earlySingletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}

四、

AbstractAutowireCapableBeanFactory抽象类

生命周期中插入了提前曝光对象的逻辑(在 doCreateBean()方法当中),变化的总共有三步:

第一步是在bean实例化后立马创建对象工厂

1
2
3
4
5
6
7
8
9
10
11
// 紧挨着实例化之后执行 创建早期曝光对象工厂并添加到三级缓存中
if (beanDefinition.isSingleton()) {
Object finalBean = bean;
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
// 这一步会提前调用AOP动态代理
return getEarlyBeanReference(beanName, beanDefinition, finalBean);
}
});
}

第二步是填充属性中调用的 getSingleton(),这一步在上面有

1
applyPropertyValues # getBean # getSingleton

第三步是添加bean到单例池中时,直接添加二级缓存中的bean单例,然后将二级缓存中的该bean移除

1
2
3
4
5
6
7
8
// doCreatBean()
Object exposedObject = bean;
if (beanDefinition.isSingleton()) {
// 如果有代理对象,此处获取代理对象
exposedObject = getSingleton(beanName);
addSingleton(beanName, exposedObject);
}
return exposedObject;
1
2
3
4
5
6
7
// DefaultSingletonBeanRegistry
@Override
public void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
earlySingletonObjects.remove(beanName);
singletonFactories.remove(beanName);
}

3. 简单示例&执行流程

假设类A、B相互依赖

**A.1. **A实例化后立马创建自己的早期曝光对象工厂并添加到三级缓存中

如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象(通过 getEarlyBeanReference()方法实现)

**A.2. **A要填充属性B

**B.1. **B也实例化后立马创建自己的早期曝光对象工厂并添加到三级缓存中

**B.2. **B要填充属性A,调用 applyPropertyValues # getBean # getSingleton,通过 getSingleton()方法,获得属性A

**B.3. **B成功填充属性,完成B的生命周期,将二级缓存中的B存储到单例池中。

**A.3. **然后A获得完整的B,完成A的生命周期,将二级缓存中的A存储到单例池中。

至此循环依赖处理完成。

当循环依赖遇上JDK动态代理,真是酣畅淋漓的一场debug qwq

注意:JDK动态代理一切基于接口,原始类和代理类是基于同一个接口的不同子实现类,二者之间的转换要通过接口来实现,倘若二者直接相互转换,便会出现报错。

4. 不能解决的循环依赖

Spring 的三级缓存机制无法解决构造函数注入之间的循环依赖。因为在构造函数注入中,Bean 在创建期间无法暴露其早期引用,而构造器注入要求在创建对象时即完成所有依赖的注入。

下面这个链接讲的不错

面试必杀技,讲一讲Spring中的循环依赖 - 程序员DMZ - 博客园 (cnblogs.com)

Spring注入方式

实例化方式有构造器实例化和工厂方式实例化

实例化后要注入属性,主要有

  • 构造器注入
  • setter方法注入
  • 字段注入

1. 构造器注入

1.1 优点

  1. 确保对象创建时依赖完整
    • 通过构造器传递依赖,确保在对象被实例化时就具备所需的所有依赖。
    • 如果缺少必要的依赖项,程序会在构造阶段立即发现问题,有助于编译时错误检测。
  2. 增强对象的不可变性
    • 通过构造器注入,可以确保被注入的依赖在对象的生命周期内保持不变,设计上更符合不可变性的最佳实践。
    • 提高了代码的稳定性和线程安全性,尤其在多线程环境中显得重要。
  3. 简化测试
    • 构造器注入更便于编写单元测试,因为依赖项可以通过构造器直接传递,而无需借助依赖注入框架或容器。
  4. 强制依赖声明
    • 构造器注入明确地表明了类的依赖关系,开发者无法忽略或遗漏必需的依赖项。
    • 有助于理解类的依赖需求,提高代码的可读性。
  5. 易于调试和维护
    • 因为构造器注入的依赖关系在实例化时就固定下来,所以调试和追踪依赖问题变得更加直接。
  6. 无需容器依赖
    • 构造器注入避免了在某些情况下必须依赖于容器框架的局限性,允许更灵活地在非容器环境中使用。

1.2 注意

  1. 如果用构造方法注入的时候,参数过多以至于代码过于臃肿,那么此时你需要考虑这个类的设计是否合理,这个类是否参杂了太多的其他无关功能,这个类是否做到了单一职责。
  2. Spring 的三级缓存机制无法解决构造函数注入之间的循环依赖。因为在构造函数注入中,Bean 在创建期间无法暴露其早期引用,而构造器注入要求在创建对象时即完成所有依赖的注入。

综合来看,构造器注入是一种非常稳健的依赖注入方式,适合在对象的依赖关系明确且稳定时使用。

2. setter方法注入

适用于当依赖是可选的,或者需要在初始化后动态改变时。

优点:提供更灵活的配置方式,允许对象在创建之后改变依赖关系。

缺点:可能导致对象在完全配置前处于不一致状态。不适用于需要不可变依赖的场景。

3. 字段注入

3.1 缺点

基于字段的依赖注入是一种常见的实现方法。然而,基于字段的依赖注入有几个明显的缺陷:

  1. 可测试性受限
    使用字段注入时,依赖通常是通过框架在运行时注入的,这意味着在不启动整个Spring容器的情况下,很难对这些组件进行单元测试。虽然可以使用反射来设置这些字段,但这种方法通常比较繁琐且容易出错。

  2. 违反封装原则
    字段注入通常需要将字段设置为非私有(例如,包级私有或者受保护的),这违反了面向对象设计的封装原则。封装原则推荐通过构造函数或者方法来管理依赖,这样可以保证类的行为不会被外部错误地改变。

  3. 隐式依赖关系

    • 难以理解

      新的开发人员或维护人员在阅读或审核代码时,可能不会立即意识到类依赖了哪些其他组件。他们需要深入检查每个字段的注解来确定依赖关系,这增加了理解和维护的难度。

    • 文档和工具支持不足

      构造器或方法注入相比,字段注入可能不会被一些自动化工具或文档生成工具如Javadoc等捕捉到,因为这些工具通常关注公共接口而非内部实现。

    相对地,构造器注入通过构造函数显式地声明依赖,使得依赖关系更加明显,便于理解和维护。

  4. 框架耦合性增加
    字段注入使得代码与Spring框架更加紧密地耦合在一起。例如,通过使用 @Autowired注解实现的依赖注入使得组件难以脱离Spring环境被复用或迁移到其他框架中。

  5. 运行时错误的可能性
    如果依赖没有被正确注入,基于字段的注入通常会在运行时才表现出问题,而构造器注入会在应用启动时立即抛出异常,因为依赖关系是通过构造器显式传递的。

  6. 不支持不可变性
    使用字段注入很难实现不可变的依赖关系,因为字段通常需要在对象创建后设置。相比之下,构造器注入支持创建完全初始化且状态不变的对象,这有助于创建线程安全的应用。

基于这些缺点,许多开发者和Spring的推荐实践趋向于使用构造器注入而不是字段注入,尽管在简单的场景下,字段注入依然是一个快速且方便的选项。

4. 总结

在实际开发中,选择使用哪种注入方式取决于具体的开发需求、代码风格和项目结构。

  • 偏好构造器注入:因为它提供了明确的依赖关系,并鼓励不可变设计。
  • 适时使用 Setter 注入:在某些配置类或依赖项需要在运行时灵活切换的情况下。
  • 谨慎使用字段注入:通常在简单的服务类或工具类中使用,但要确保不会影响测试或代码可维护性。

扯一把 Spring 的三种注入方式,到底哪种注入方式最佳? - 掘金 (juejin.cn)

公司为什么禁止在SpringBoot项目中使用@Autowired注解 - 掘金 (juejin.cn)

懒加载

XmlBeanDefinitionReader中添加对 lazyInit属性的解析

beanDefinition中加入 lazyInit属性

DefaultListableBeanFactory中添加对 isLazyInit的处理

1
2
3
4
5
6
7
8
@Override
public void preInstantiateSingletons() throws BeansException {
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
if(beanDefinition.isSingleton() && !beanDefinition.isLazyInit()){
getBean(beanName);
}
});
}

拦截器链

1. ProxyFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ProxyFactory extends AdvisedSupport {

public ProxyFactory() {
}

public Object getProxy() {
return createAopProxy().getProxy();
}

/**
* 自动判断使用JDK还是CGLIB动态代理
* @return 返回代理对象
*/
private AopProxy createAopProxy() {
if (this.isProxyTargetClass() || this.getTargetSource().getTargetClass().length==0) {
return new CglibAopProxy(this);
}
return new JdkDynamicAopProxy(this);
}
}

2. AdvisedSupport

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 代理方式(默认JDK动态代理)
public boolean proxyTargetClass = false;

// 目标对象
private TargetSource targetSource;

// 方法匹配器
private MethodMatcher methodMatcher;

// 缓存拦截器链
private transient Map<Integer, List<Object>> methodCache;

// 拦截器链工厂
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

// 所有的Advisor实例(每一个Advisor包含一个切面Advice和一个切点Pointcut)
private List<Advisor> advisors = new ArrayList<>();

//...

// 返回拦截器链
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
// 方法的哈希码作为键
Integer cacheKey = method.hashCode();
// 根据缓存键获取已缓存的拦截器列表
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 获取拦截器和动态拦截器通知
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
// 将获取到的拦截器列表放入方法缓存中
this.methodCache.put(cacheKey, cached);
}
return cached;
}

3. 基于JDK动态代理

  1. 获取拦截器链
  2. 将拦截器统一封装成ReflectiveMethodInvocation
  3. 执行拦截器链
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取目标对象
Object target = advised.getTargetSource().getTarget();
Class<?> targetClass = target.getClass();
Object retVal = null;
// 1. 获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain == null || chain.isEmpty()) {
// 如果拦截器链为空,那就执行原有方法
return method.invoke(target, args);
// 如果拦截器链不为空
} else {
// 2. 将拦截器统一封装成ReflectiveMethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 3. 执行拦截器链
retVal = invocation.proceed();
}
return retVal;
}

4. 获取拦截器链

拦截器链工厂,就是将 AdvisedSupport中所有满足条件的 advisor都放进一个集合当中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class DefaultAdvisorChainFactory implements AdvisorChainFactory {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport config, Method method, Class<?> targetClass) {

// 从 AdvisedSupport 对象中获取所有的 Advisor 实例,将它们转化为 Advisor 数组。
Advisor[] advisors = config.getAdvisors().toArray(new Advisor[0]);

// 拦截器链容器
List<Object> interceptorList = new ArrayList<>(advisors.length);

// 确定实际的类:如果传入的 targetClass 不为空,则使用 targetClass;如果为空,则使用方法所属的类。
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());

// 遍历所有的 Advisor,将满足条件的 Advisor 处理为 MethodInterceptor 加入到 interceptorList。
for (Advisor advisor : advisors) {
// 检查 Advisor 是否为 PointcutAdvisor 类型。只有 PointcutAdvisor 才有 Pointcut 和 MethodMatcher 的概念
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 通过 Pointcut 中的 ClassFilter 来检查该 Advisor 是否适用于当前类。如果适用,则继续检查方法。
if (pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 使用 matches 方法检查 Advisor 是否适用于当前的方法。(底层用到了aspectj框架,原理暂时不会)
match = mm.matches(method,actualClass);
if (match) {
// 如果匹配成功,将 Advisor 中的 Advice 转换为 MethodInterceptor 并加入到 interceptorList 中。
MethodInterceptor interceptor = (MethodInterceptor) advisor.getAdvice();
interceptorList.add(interceptor);
}
}
}
}
return interceptorList;
}
}

5. 将拦截器统一封装成ReflectiveMethodInvocation

完善 ReflectiveMethodInvocation成员变量,重写 proceed()方法,使之支持多切面

6. 执行拦截器链

使用递归的方式来使之顺序执行

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public Object proceed() throws Throwable {
// 初始currentInterceptorIndex为-1,每调用一次proceed就把currentInterceptorIndex+1
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 当调用次数 = 拦截器个数时
// 触发当前method方法
return method.invoke(this.target, this.arguments);
}
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 普通拦截器,内部还会继续调用proceed()方法,直接触发拦截器invoke方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

以两个 After和两个 before为例

image-20240505211810554

7._责任链模式

责任链模式是一种行为设计模式,它允许多个对象都有机会处理请求,将这些对象连成一条链。责任链中的每个对象都包含对下一个对象的引用,并在处理请求时要么自行处理,要么将请求传递给链中的下一个对象。

Spring AOP中,递归调用拦截器链中的每一个节点,根据拦截器的实现来决定插入逻辑的顺序。


一是深度,二是广度,知识一定要有体系。

解析xml文件的好几种方式

解析properties文件的方式

解析注解的方式