Spring源码学习
Spring源码学习
- 第一章bean的元数据
- 一、bean的注入方式
- 二、BeanDefinition详解
- 三、BeanDefinition注册器
- 四、加载BeanDefinition
- 五、包扫描源码
- 第二章 基础工具
- 一、内省api
- 二、更强的反射工具
- 三、ResolvableType
- 四、类型转化
- 1、转换服务
- 2、converter结构
- 五、resource匹配
- 1、内置的Resource的实现
- 2、加载xml
- 六、环境
- 1. **Profiles**(配置分组)
- 2. **Properties**(属性配置)
- 七、发布订阅
- 1. 概述
- 2. 源码阅读
- 第三章 容器和上下文
- 一、认识bean工厂
- 1、基础能力
- 2、更强大的枚举能力
- 3、灵活的分层能力
- 4、构建和自动装配的能力
- 5、更强的配置能力
- 6、工厂的生命周期
- 二、bean工厂的创建
- FactoryBean
- 三、了解扩展点
- 四、认识ApplicationContext
- 第四章 刷新容器
- 1、准备刷新:prepareRefresh源码
- 2、获得一个新鲜的bean工厂:obtainFreshBeanFactory源码
- 3、为bean工厂做一些前期的准备:prepareBeanFactory(beanFactory)
- 4、留给子类做后置处理的函数
- 5、调用bean工厂的后置处理器
- 6、注册bean的后置处理器
- 7.初始化消息源➡8.初始化多播器➡9.`onRefresh()`
- 10、注册listener
- 11、注册非懒加载的单例bean
- 12、完成刷新
- 第五章 循环引用
- 1、产生的问题
- 2、基础解决方案
- 3、有代理的循环依赖
- 第六章 扩展
第一章bean的元数据
一、bean的注入方式
- xml
<beah id="user" class="com. ydlclass.user" scope=" prototype" autowire="byType" init-method="init" depends-on="a,b" ><property name= "name" value="jerry"/><property name="age" value="18"/>
</bean>
- 注解
@Controller
public class UserController{}
@Service
public class UserService{}
@Repository
public class UserService{}
@Compoment
public class UserService{}
- 配置类
@Configuration
public class UserConfiguration {@Bean("user")public User user(){User user = new user());user.setName("lily");user.setAge(20);return user;}
}
- import注解
public class MySelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.ydlclass.UserService", "com.ydlclass.UserDao"};}
}@Configuration
@Import(MySelector.class)
public class UserConfiguration {}
二、BeanDefinition详解
bean存在多种不同的元数据,Spring在构造bean时,需要将千差万别的class概括成一种统一的描述性语言,Spring提供了一个接口BeanDefinition
统一了这种描述bean的元数据。
一个BeanDefinition大概保存了以下信息:
- 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
- 具体的工厂方法(CIass类型),包括工厂方法的返回类型,工厂方法的Method对象
- 构造函数、构造函数形参类型
- Bean的class对象
- 作用范围、是否懒加载等等
- BeanDefinition接口定义了一些基础的数据
- AbstractBeanDefinition抽象类在接口上提供了一些基础的实现
- 具体的实现类细化了方法的实现,提供了不同的解决方案
(不同实现类事件的处理上采取不一样的策略,但都实现了同一个接口,这就是多态的表现)
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.beans.factory.config;import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;/*** BeanDefinition 接口描述了 Spring 容器中的 Bean 的配置元数据。* 它定义了 bean 的属性、依赖关系、作用域以及生命周期方法。*/
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {// 常量定义 Bean 的作用域 - 单例String SCOPE_SINGLETON = "singleton";// 常量定义 Bean 的作用域 - 原型String SCOPE_PROTOTYPE = "prototype";// Bean 的角色 - 应用级别int ROLE_APPLICATION = 0;// Bean 的角色 - 支持类(如工具类)int ROLE_SUPPORT = 1;// Bean 的角色 - 基础设施类(框架内部使用)int ROLE_INFRASTRUCTURE = 2;// 设置父 Bean 的名称,用于 Bean 配置的继承void setParentName(@Nullable String parentName);// 获取父 Bean 的名称@NullableString getParentName();// 设置该 Bean 的类名(全限定名)void setBeanClassName(@Nullable String beanClassName);// 获取该 Bean 的类名(全限定名)@NullableString getBeanClassName();// 设置该 Bean 的作用域(如 singleton 或 prototype)void setScope(@Nullable String scope);// 获取该 Bean 的作用域@NullableString getScope();// 设置该 Bean 是否懒加载(lazy-init),若为 true,Bean 将在首次使用时初始化void setLazyInit(boolean lazyInit);// 获取该 Bean 是否懒加载boolean isLazyInit();// 设置该 Bean 的依赖项,即必须在这些 Bean 初始化之后才能初始化此 Beanvoid setDependsOn(@Nullable String... dependsOn);// 获取该 Bean 的依赖项@NullableString[] getDependsOn();// 设置该 Bean 是否为自动装配的候选者void setAutowireCandidate(boolean autowireCandidate);// 获取该 Bean 是否为自动装配的候选者boolean isAutowireCandidate();// 设置该 Bean 是否为主要的自动装配候选者(primary)void setPrimary(boolean primary);// 获取该 Bean 是否为主要的自动装配候选者boolean isPrimary();// 设置工厂 Bean 的名称,用于实例化该 Bean 的工厂类void setFactoryBeanName(@Nullable String factoryBeanName);// 获取工厂 Bean 的名称@NullableString getFactoryBeanName();// 设置工厂方法的名称,使用工厂方法来创建该 Bean 实例void setFactoryMethodName(@Nullable String factoryMethodName);// 获取工厂方法的名称@NullableString getFactoryMethodName();// 获取构造函数参数的值ConstructorArgumentValues getConstructorArgumentValues();// 检查是否有构造函数参数值default boolean hasConstructorArgumentValues() {return !this.getConstructorArgumentValues().isEmpty();}// 获取 Bean 的属性值,用于依赖注入MutablePropertyValues getPropertyValues();// 检查是否有属性值default boolean hasPropertyValues() {return !this.getPropertyValues().isEmpty();}// 设置初始化方法的名称,该方法将在 Bean 完成初始化时调用void setInitMethodName(@Nullable String initMethodName);// 获取初始化方法的名称@NullableString getInitMethodName();// 设置销毁方法的名称,该方法将在 Bean 被销毁时调用void setDestroyMethodName(@Nullable String destroyMethodName);// 获取销毁方法的名称@NullableString getDestroyMethodName();// 设置 Bean 的角色(应用、支持或基础设施)void setRole(int role);// 获取 Bean 的角色int getRole();// 设置 Bean 的描述信息void setDescription(@Nullable String description);// 获取 Bean 的描述信息@NullableString getDescription();// 获取该 Bean 的可解析类型(用于泛型处理)ResolvableType getResolvableType();// 判断该 Bean 是否为单例作用域boolean isSingleton();// 判断该 Bean 是否为原型作用域boolean isPrototype();// 判断该 Bean 是否为抽象类,抽象 Bean 不能实例化boolean isAbstract();// 获取该 Bean 定义的资源描述(例如 XML 文件的位置)@NullableString getResourceDescription();// 获取原始的 BeanDefinition(例如通过继承生成的 BeanDefinition)@NullableBeanDefinition getOriginatingBeanDefinition();
}
GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition异同:
GenericBeanDefinition
、RootBeanDefinition
和 ChildBeanDefinition
是 Spring 框架中常见的三种 BeanDefinition
实现
GenericBeanDefinition
是 Spring 3.0 引入的一个通用 Bean 定义类,它没有附加的约束,几乎可以替代RootBeanDefinition
和ChildBeanDefinition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(MyService.class);
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
RootBeanDefinition
是早期 Spring 版本中常用的BeanDefinition
实现之一,通常用于定义独立的 Bean,也就是没有父 Bean的 Bean。
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(MyService.class);
rootBeanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
ChildBeanDefinition
是用于定义子 Bean 的BeanDefinition
实现,允许继承其他 Bean 的配置。
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("parentBean");
childBeanDefinition.getPropertyValues().add("propertyName", "value");
三、BeanDefinition注册器
有了统一的标准的元数据后,我们可以进行统一的管理,此时需要一个容器去存储。
可以使用map这样的集合类,当然spring差不多是这么做的,它提供了一个接口BeanDefinitionRegistry
。
只要实现了这个接口,就会有注册BeanDefinition的能力。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.beans.factory.support;import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.AliasRegistry;/*** BeanDefinitionRegistry 是 Spring 中 Bean 定义注册的核心接口,* 它允许在 Spring 容器中注册、移除和获取 BeanDefinition。* 这个接口扩展了 AliasRegistry,用于处理 Bean 的别名。*/
public interface BeanDefinitionRegistry extends AliasRegistry {/*** 注册给定名称的 BeanDefinition。** @param beanName Bean 的名称* @param beanDefinition 要注册的 BeanDefinition* @throws BeanDefinitionStoreException 如果 BeanDefinition 无法存储*/void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;/*** 移除给定名称的 BeanDefinition。** @param beanName 要移除的 Bean 的名称* @throws NoSuchBeanDefinitionException 如果找不到指定的 BeanDefinition*/void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;/*** 根据名称获取 BeanDefinition。** @param beanName Bean 的名称* @return 指定名称的 BeanDefinition* @throws NoSuchBeanDefinitionException 如果找不到指定的 BeanDefinition*/BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;/*** 检查是否包含给定名称的 BeanDefinition。** @param beanName 要检查的 Bean 名称* @return 如果包含 BeanDefinition 则返回 true,否则返回 false*/boolean containsBeanDefinition(String beanName);/*** 获取所有已注册的 BeanDefinition 名称。** @return 所有 BeanDefinition 名称的数组*/String[] getBeanDefinitionNames();/*** 获取已注册的 BeanDefinition 总数。** @return BeanDefinition 的数量*/int getBeanDefinitionCount();/*** 检查给定名称的 BeanDefinition 是否可以被覆盖。** @param beanName 要检查的 Bean 名称* @return 默认返回 true,表示可以被覆盖*/default boolean isBeanDefinitionOverridable(String beanName) {return true;}/*** 检查给定的 Bean 名称是否正在使用中(包括别名和实际 Bean 名称)。** @param beanName 要检查的 Bean 名称* @return 如果名称正在使用中则返回 true,否则返回 false*/boolean isBeanNameInUse(String beanName);
}
以SimpleBeanDefinitionRegistry
为例子,看其源码:
package org.springframework.beans.factory.support;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.SimpleAliasRegistry;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;// SimpleBeanDefinitionRegistry 类实现了 BeanDefinitionRegistry 接口,
// 用于注册和管理 BeanDefinition。
public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {// 存储 BeanDefinition 的映射,使用线程安全的 ConcurrentHashMap。private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);// 构造函数public SimpleBeanDefinitionRegistry() {}// 注册 BeanDefinition,使用指定的 beanName 和 BeanDefinition。public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {// 确保 beanName 非空Assert.hasText(beanName, "'beanName' must not be empty");// 确保 beanDefinition 不为空Assert.notNull(beanDefinition, "BeanDefinition must not be null");// 将 BeanDefinition 存入 mapthis.beanDefinitionMap.put(beanName, beanDefinition);}// 移除指定名称的 BeanDefinition。public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {// 尝试从 map 中移除 beanDefinition,若未找到则抛出异常if (this.beanDefinitionMap.remove(beanName) == null) {throw new NoSuchBeanDefinitionException(beanName);}}// 获取指定名称的 BeanDefinition。public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {// 从 map 中获取 BeanDefinitionBeanDefinition bd = this.beanDefinitionMap.get(beanName);// 若未找到,抛出异常if (bd == null) {throw new NoSuchBeanDefinitionException(beanName);} else {return bd;}}// 检查是否包含指定名称的 BeanDefinition。public boolean containsBeanDefinition(String beanName) {return this.beanDefinitionMap.containsKey(beanName);}// 获取所有注册的 BeanDefinition 名称。public String[] getBeanDefinitionNames() {return StringUtils.toStringArray(this.beanDefinitionMap.keySet());}// 获取当前注册的 BeanDefinition 的数量。public int getBeanDefinitionCount() {return this.beanDefinitionMap.size();}// 检查给定的 beanName 是否正在使用(即是否是别名或存在的 BeanDefinition)。public boolean isBeanNameInUse(String beanName) {return this.isAlias(beanName) || this.containsBeanDefinition(beanName);}
}
SimpleBeanDefinitionRegistry
使用了ConcurrentHashMap当作容器,对bean进行简单的管理
构造器的使用:
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.*;public class SimpleBeanDefinitionRegistryExample {public static void main(String[] args) {// 创建 SimpleBeanDefinitionRegistry 实例SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();// 创建 BeanDefinitionBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);// 注册 BeanDefinitionregistry.registerBeanDefinition("myBean", beanDefinition);}
}// 示例 Bean 类
class MyBean {// Bean 的属性和方法
}
四、加载BeanDefinition
- 读取xml配置文件
// 定义一个注册器,用来注册和管理 BeanDefinition
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
// 通过 XML 文件加载
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(registry);
//加载xml文件,将bean注册到注册器中
xmlReader.loadBeanDefinitions("classpath:spring.xml");
- 加载带注解的Bean
// 定义一个注册器,用来注册和管理 BeanDefinition
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
// 通过注解加载
AnnotatedBeanDefinitionReader annoReader = new AnnotatedBeanDefinitionReader(registry);
// 注册 User 类
annoReader.register(User.class);
- 读取配置类
ConfigurationClassBeanDefinitionReader
是 Spring 框架内部用于处理配置类的一个类,它负责读取带有@Configuration
注解的类并注册其定义的 Bean。 - 类路径扫描
// 定义一个注册器,用来注册和管理 BeanDefinition
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();// 通过扫描包的方式
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.scan("com.ydlclass");
五、包扫描源码
解析一个类的方式:
- 加载一个类到内存,获取Class对象,通过反射获取元数据
- 直接操纵字节码文件(.class),读取字节码内的元数据
spring选择的是第二种
- 第二种性能要优于第一种,省略类加载的过程
- 第一种会将扫描的类全部都加载到堆内存,会浪费空间,增加gc次数,第二种可以根据元数据按需加载
- 类加载和内存使用
- 反射方式(第一种方式):
反射依赖于 JVM 将类加载到内存中,必须首先通过ClassLoader
将类的.class
文件加载到堆内存。这意味着每个被解析的类都需要被 JVM 加载,并且占用内存。当你解析大量类时,所有这些类对象都会驻留在内存中,导致内存使用增加,垃圾回收(GC)次数和频率可能会增加。- 缺点:
加载不必要的类会浪费内存,尤其是在只需要访问类的元数据时。- 直接操作字节码(第二种方式):
直接解析.class
文件时,类并不需要被 JVM 加载到堆内存中。你可以仅通过读取.class
文件内容获取元数据,而不需要将整个类实例化。这意味着你可以根据需要按需访问和处理类的元数据,而不必加载整个类。- 优点:你可以更加高效地控制哪些类被处理,减少不必要的内存占用和 GC 开销。
- 性能差异
- 反射的运行时开销:由于反射在运行时需要动态查找类、方法和字段,且要进行权限检查等操作,因此相比于直接读取字节码的方式,反射的操作速度较慢,特别是在频繁调用反射 API 的场景下。反射本质上是通过 JVM 提供的 API 间接访问类的信息,会有一定的开销。
- 直接操作字节码的效率:操作字节码文件则跳过了类加载和权限检查步骤,直接从字节码文件中提取类信息,性能更加高效。由于直接从磁盘或内存中读取
.class
文件,处理速度更快,而且可以避免 JVM 的动态查找和检查过程。
- 按需加载 vs 完整加载
- 反射:反射机制一般会加载整个类,即使你只需要获取某些元数据(如方法名、字段名),但类的所有元数据都会被加载到内存中。
- 直接操作字节码:你可以通过读取
.class
文件的字节码结构按需提取元数据,而无需加载整个类或实例化对象。你可以只读取所需的部分信息,例如类的常量池、方法描述符等,从而提升性能和内存利用效率。
Java 中的反射解析的是JVM 中已经加载到内存中的类对象(Class
对象)。这些类对象是由 JVM 在加载 .class
文件时生成的。当 Java 程序运行时,JVM 会将 .class
文件加载到内存中,并创建一个与该类对应的 Class
对象。这个 Class
对象包含了该类的元数据(如类名、方法、字段、构造函数、注解等),并且通过 Java 的反射机制可以访问这些元数据。
接下来对ClassPathBeanDefinitionScanner的scan方法进行源码解析:
public int scan(String... basePackages) {// 获取当前注册表中的 Bean 定义数量,并存储在变量 beanCountAtScanStart 中,用于后续计算新增的 Bean 数量int beanCountAtScanStart = this.registry.getBeanDefinitionCount();// 调用 doScan 方法,传入 basePackages 参数,开始扫描指定的包路径中的 Bean 定义this.doScan(basePackages);// 如果 includeAnnotationConfig 为 true,则注册注解配置的处理器(如 @Configuration、@Component 等)// 这将确保这些注解可以正常工作,通常用于 Spring 的注解驱动的配置if (this.includeAnnotationConfig) {AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}// 返回扫描后注册表中新增的 Bean 定义数量// 计算方式是当前 Bean 定义总数减去扫描开始前的数量return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}
核心方法是doScan函数:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {// 检查传入的包路径参数 basePackages 是否为空,若为空则抛出异常Assert.notEmpty(basePackages, "At least one base package must be specified");// 创建一个空的 LinkedHashSet 集合用于存储扫描到的 BeanDefinitionHolderSet<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();// 遍历传入的包路径(basePackages),获取要扫描的包路径String[] var3 = basePackages;int var4 = basePackages.length;for (int var5 = 0; var5 < var4; ++var5) {// 获取当前遍历到的包路径String basePackage = var3[var5];// 调用 findCandidateComponents 方法,查找该包路径下所有符合条件的 Bean 定义Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);Iterator var8 = candidates.iterator();// 遍历所有符合条件的 BeanDefinitionwhile (var8.hasNext()) {BeanDefinition candidate = (BeanDefinition) var8.next();// 解析每个 Bean 的作用域(scope),并设置到 BeanDefinition 中ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());// 生成 Bean 的名称(beanName)String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);// 如果 BeanDefinition 是 AbstractBeanDefinition 类型,执行后置处理if (candidate instanceof AbstractBeanDefinition) {AbstractBeanDefinition abstractBeanDefinition = (AbstractBeanDefinition) candidate;this.postProcessBeanDefinition(abstractBeanDefinition, beanName);}// 如果 BeanDefinition 是 AnnotatedBeanDefinition 类型,处理常用注解(如 @Lazy、@Primary 等)if (candidate instanceof AnnotatedBeanDefinition) {AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) candidate;AnnotationConfigUtils.processCommonDefinitionAnnotations(annotatedBeanDefinition);}// 检查是否可以注册该 Bean(检查重复定义等情况)if (this.checkCandidate(beanName, candidate)) {// 将 BeanDefinition 封装到 BeanDefinitionHolder 中BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);// 应用作用域代理模式(如果需要),比如为 request、session 等作用域创建代理对象definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);// 将 BeanDefinitionHolder 添加到集合中beanDefinitions.add(definitionHolder);// 注册该 BeanDefinition 到 BeanFactory(将其注册到 Spring 容器中)this.registerBeanDefinition(definitionHolder, this.registry);}}}// 返回扫描得到的 BeanDefinitionHolder 集合return beanDefinitions;
}
再看查找候选者candidate的相关代码:
public Set<BeanDefinition> findCandidateComponents(String basePackage) {// 判断是否存在组件索引(componentsIndex)且索引支持包含过滤器(include filters)// 如果存在组件索引并支持过滤器,则从索引中添加候选组件return this.componentsIndex != null && this.indexSupportsIncludeFilters() // 如果有组件索引,并且支持过滤器,则通过索引来获取候选组件? this.addCandidateComponentsFromIndex(this.componentsIndex, basePackage) // 否则通过扫描的方式获取候选组件: this.scanCandidateComponents(basePackage);
}
Spring 5 的新特性,直接从 META-INF/spring.components 组件索引文件中加载符合条件的 Bean,避免了包扫描,用于提升启动速度。
Spring 5 升级的其中一个重点就是提升了注解驱动的启动性能。META-INF/spring.components 这个文件类似于一个 “组件索引” 文件。
我们将需要加载的组件 (Bean 定义) 预先以键值对的形式配置到该文件中。当项目中存在 META-INF/spring.components 文件并且文件中配置了属性时,Spring 不会进行包扫描,而是直接读取 META-INF/spring.components 中组件的定义并直接加载,从而达到提升性能的目的。
如META-INF/spring.components记录了:
com.ydLcLass.Dog=org.springframework.stereotype.Component
com.ydLcLass.MyConfiguration=org.springframework.stereotype.Component
则会将Dog、MyConfiguration注册为@Component
进一步查看候选者的扫描:
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {// 创建一个 LinkedHashSet 用于存储扫描到的候选 BeanDefinition 对象LinkedHashSet candidates = new LinkedHashSet();try {// 将包名转换为资源路径String var10000 = this.resolveBasePackage(basePackage);// 构建扫描路径,形如 "classpath*:com/example/**/*.class"String packageSearchPath = "classpath*:" + var10000 + "/" + this.resourcePattern;// 获取匹配路径的所有资源(类文件、配置文件等)//Spring会将每一个定义的字节码文件加载成为一个Resource资源(包括内部类都是一个Resource资源)//此处是以资源(流)的方式加载(普通文件),而不是将一个类使用类加载器加载到jvm中。Resource[] resources = this.getResourcePatternResolver().getResources(packageSearchPath);// 检查日志级别是否为 trace 或 debugboolean traceEnabled = this.logger.isTraceEnabled();boolean debugEnabled = this.logger.isDebugEnabled();Resource[] var7 = resources;int var8 = resources.length;// 遍历扫描到的资源for (int var9 = 0; var9 < var8; ++var9) {Resource resource = var7[var9];String filename = resource.getFilename();// 跳过包含 "$$" 的类(通常是由代理生成的类,如CGLIB生产的代理类文件)if (filename == null || !filename.contains("$$")) {// 如果启用了 trace 日志,则记录正在扫描的资源if (traceEnabled) {this.logger.trace("Scanning " + resource);}try {// 通过 MetadataReader 读取资源的元数据MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource);// 检查该资源是否是候选组件,即是否符合TypeFilter类型过滤器的要求//使用IncludeFilter。 就算目标类上没有@Component注解,它也会被扫描成为一-个Bean//使用ExcludeFilter, 就算目标类上面有QComponent注解也不会成为Beanif (this.isCandidateComponent(metadataReader)) {// 如果是候选组件,创建 BeanDefinitionScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setSource(resource);// 进一步验证该组件是否是合格的候选组件if (this.isCandidateComponent((AnnotatedBeanDefinition) sbd)) {// 如果启用了 debug 日志,记录该候选组件if (debugEnabled) {this.logger.debug("Identified candidate component class: " + resource);}// 将合格的组件添加到 candidates 集合中candidates.add(sbd);} else if (debugEnabled) {// 如果该类不是具体的顶级类,记录 debug 日志this.logger.debug("Ignored because not a concrete top-level class: " + resource);}} else if (traceEnabled) {// 如果不符合筛选条件,记录 trace 日志this.logger.trace("Ignored because not matching any filter: " + resource);}} catch (FileNotFoundException var14) {// 如果资源文件找不到,记录 trace 日志并跳过该资源if (traceEnabled) {this.logger.trace("Ignored non-readable " + resource + ": " + var14.getMessage());}} catch (ClassFormatException var15) {// 如果类格式异常,根据配置决定是否忽略该异常if (!shouldIgnoreClassFormatException) {throw new BeanDefinitionStoreException("Incompatible class format in " + resource + ": set system property 'spring.classformat.ignore' to 'true' if you mean to ignore such files during classpath scanning", var15);}if (debugEnabled) {// 记录 debug 日志,表示类格式不兼容被忽略this.logger.debug("Ignored incompatible class format in " + resource + ": " + var15.getMessage());}} catch (Throwable var16) {// 捕获任何其他异常并抛出 BeanDefinitionStoreException 异常throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var16);}}}// 返回扫描到的候选组件return candidates;} catch (IOException var17) {// 捕获 I/O 异常并抛出 BeanDefinitionStoreException 异常throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var17);}
}
第二章 基础工具
一、内省api
内省(Introspection)是 Java 语言中用于 Bean 类属性和事件处理的机制,通过它可以动态地获取类的信息,尤其是 Bean 类的属性和事件。内省允许程序在运行时检查对象及其类的特性,而不需要提前知道对象的具体类型。
内省机制是一种 Java 提供的动态分析类信息的手段,Spring 使用该机制自动处理 Bean 的依赖注入、事件监听等功能,大大提高了开发的灵活性和自动化程度。
扩:反射 V S VS VS内省
- 内省:专注于 Java Bean 类的属性和事件的获取与设置,使用相对简单,主要处理符合 Bean 规范的类。
- 反射:更为通用和强大的机制,允许操作类的所有成员,但使用复杂度和性能开销较大。
JavaBean 与普通类的区别:
虽然 JavaBean 只是一个类,但它与普通类有几点不同:
- JavaBean 必须遵循特定的命名约定(如
getter
和setter
方法)。- JavaBean 必须有一个无参的构造函数。
- JavaBean 必须实现
Serializable
接口。- JavaBean 主要用于封装数据,通常不包含复杂的业务逻辑。
内省机制是通过 Introspector
类获取 BeanInfo
,然后通过 BeanInfo
获取属性描述器 PropertyDescriptor
,最终利用这些描述器来获取属性的 getter 和 setter 方法,从而通过反射调用这些方法进行属性的操作。
public void testIntrospect() throws Exception {// 获取 User 类的 BeanInfo 对象,不包含从 Object 类继承的属性BeanInfo info = Introspector.getBeanInfo(User.class, Object.class);// 获取该类的所有属性描述器PropertyDescriptor[] pds = info.getPropertyDescriptors();// 遍历每个属性描述器for (PropertyDescriptor pd : pds) {// 获取属性的名称并记录到日志logger.info("pd.getName() --> {}", pd.getName());// 获取属性的 getter 方法并记录到日志logger.info("pd.getReadMethod() --> {}", pd.getReadMethod());// 获取属性的 setter 方法并记录到日志logger.info("pd.getWriteMethod() --> {}", pd.getWriteMethod());// 获取属性的类型并记录到日志logger.info("pd.getPropertyType() --> {}", pd.getPropertyType());// 获取属性的简短描述并记录到日志logger.info("pd.getShortDescription() --> {}", pd.getShortDescription());}
}
当涉及到设置值,就使用到了反射的函数:
public void testIntrospect() throws Exception {// 创建一个 User 对象User user = new User();// 创建一个 PropertyDescriptor,用于描述 User 类的 "age" 属性PropertyDescriptor descriptor = new PropertyDescriptor("age", User.class);// 获取该属性的 setter 方法Method writeMethod = descriptor.getWriteMethod();// 使用反射调用 setter 方法,将 age 属性的值设置为 13writeMethod.invoke(user, 13);// 记录当前 user 对象的状态,输出 user 对象的信息Logger.info("user --> {}", user);// 获取该属性的 getter 方法Method readMethod = descriptor.getReadMethod();// 使用反射调用 getter 方法,获取 age 属性的值,并记录到日志Logger.info("age --> {}", readMethod.invoke(user));
}
在 Spring 中,BeanUtils
是一个非常有用的工具类,主要用于简化 JavaBean 的操作。
- 导包
<dependency><groupId>commons-beanutils</ groupId><artifactId>commons-beanutils</ artifactId><version>1.9.4</version>
</ dependency>
二、更强的反射工具
BeanWrapper
是 Spring 框架中用于操作 JavaBean 属性的一个核心工具类。它封装了 Java 的反射机制,简化了对 JavaBean 属性的读取、设置、类型转换等操作。在 Spring 框架内部,BeanWrapper
通常与 BeanFactory
和 BeanDefinition
配合使用,用于管理和实例化 Bean。
例子:获取bean元数据并完成初始化
public void testBeanWrapper() throws ClassNotFoundException {// 通过包扫描获取的 Bean 元数据GenericBeanDefinition beanDefinition = new GenericBeanDefinition();// 设置 Bean 类的名称(全限定类名)beanDefinition.setBeanClassName("com.ydlclass.User");// 创建一个用于保存属性值的对象MutablePropertyValues values = new MutablePropertyValues();// 添加属性 "username",值为 "tom"values.addPropertyValue("username", "tom");// 添加属性 "age",值为 12values.addPropertyValue("age", 12);// 将属性值设置到 BeanDefinition 中beanDefinition.setPropertyValues(values);// 获取类的 Class 对象,通过类名加载类Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());// 创建一个 BeanWrapper 对象,使用 clazz 进行实例化BeanWrapper beanWrapper = new BeanWrapperImpl(clazz);// 设置属性值,将 BeanDefinition 中的属性值注入到 Bean 实例中beanWrapper.setPropertyValues(beanDefinition.getPropertyValues());// 获取实例化后的 Bean 对象Object instance = beanWrapper.getWrappedInstance();// 输出实例对象的内容到日志Logger.info("obj --> {}", instance);//obj --> User-username= 'tom' age=12}
}
批量构造:
// 1. 通过任意形式捕获 beanDefinition
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(registry);// 从指定的 XML 配置文件加载 Bean 定义
xmlReader.loadBeanDefinitions("classpath:bean.xml");// 2. 通过反射实例化
String[] definitionNames = registry.getBeanDefinitionNames();// 遍历所有的 Bean 定义名称
for (String definitionName : definitionNames) {// 获取 BeanDefinition 对象BeanDefinition beanDefinition = registry.getBeanDefinition(definitionName);// 获取 Bean 的类名String beanClassName = beanDefinition.getBeanClassName();// 通过类名加载该类,返回 Class 对象Class<?> aClass = Class.forName(beanClassName);// 3. 使用 BeanWrapper 包裹实例,使其更方便使用反射方法BeanWrapper beanWrapper = new BeanWrapperImpl(aClass);// 设置属性值,将 BeanDefinition 中的属性值注入到 Bean 实例中beanWrapper.setPropertyValues(beanDefinition.getPropertyValues());// 获取实例化后的 Bean 对象Object bean = beanWrapper.getWrappedInstance();// 输出 Bean 对象的信息(取决于该类的 toString 方法)System.out.println(bean);
}
目前还存在一个格式转换的问题
三、ResolvableType
ResolvableType
是一个非常强大的工具类,它简化了 Java 反射 API 的使用,尤其是在处理复杂的泛型类型时,它能方便地解析字段、方法参数、返回类型及超类、接口的泛型参数。在 Spring 框架中,ResolvableType
被广泛用于处理泛型依赖注入、事件机制以及其他需要动态解析类型的场景。
例子:
import org.springframework.core.ResolvableType;
import java.util.List;public class ResolvableTypeExample {// 定义一个具有泛型的字段private List<String> strings;public static void main(String[] args) throws NoSuchFieldException {// 获取字段的 ResolvableTypeResolvableType type = ResolvableType.forField(ResolvableTypeExample.class.getDeclaredField("strings"));// 获取该字段的原始类型,即 ListSystem.out.println("Raw class: " + type.getRawClass());// 获取该字段的泛型参数类型,即 StringSystem.out.println("Generic type: " + type.getGeneric(0).resolve());}
}
输出:
Raw class: interface java.util.List
Generic type: class java.lang.String
四、类型转化
我们从xml中搜集到的所有数据都是【字符串】,但是实际的类中的成员变量可能是数字,数组,集合,或者是复杂的引用数据类型,所以spring给我们提供了强大的转换服务(conversionService
接口) .
1、转换服务
ConversionService
接口可以根据源类型和目标类型进行判断是否可以转换,并执行转换:
public interface ConversionService {/*** 判断是否可以将源类型转换为目标类型。* @param sourceType 源类型,可以为空。* @param targetType 目标类型,不能为空。* @return 如果可以转换,返回true,否则返回false。*/boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);/*** 判断是否可以将源类型描述符表示的类型转换为目标类型描述符表示的类型。* @param sourceType 源类型描述符,可以为空。* @param targetType 目标类型描述符,不能为空。* @return 如果可以转换,返回true,否则返回false。*/boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);/*** 将给定的源对象转换为目标类型。* @param <T> 目标类型的类型参数。* @param source 源对象,可以为空。* @param targetType 目标类型,不能为空。* @return 转换后的对象,如果转换失败或源对象为空,返回null。*/@Nullable<T> T convert(@Nullable Object source, Class<T> targetType);/*** 将给定的源对象从源类型描述符表示的类型转换为目标类型描述符表示的类型。* @param source 源对象,可以为空。* @param sourceType 源类型描述符,可以为空。* @param targetType 目标类型描述符,不能为空。* @return 转换后的对象,如果转换失败或源对象为空,返回null。*/Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}
接下来看一个具体的实现类:
/*** DefaultConversionService 是一个继承自 GenericConversionService 的默认转换服务,* 提供了丰富的默认转换器,并且支持线程安全的单例模式。*/
public class DefaultConversionService extends GenericConversionService {// 共享的 DefaultConversionService 实例,用于单例模式@Nullableprivate static volatile DefaultConversionService sharedInstance;// 构造函数,实例化时自动添加默认的转换器public DefaultConversionService() {addDefaultConverters(this); // 向当前实例添加默认转换器}/*** 获取共享的单例 DefaultConversionService 实例。* 如果实例不存在,会初始化一个新实例。*/public static ConversionService getSharedInstance() {// 获取已有的 sharedInstance,如果已存在则返回DefaultConversionService cs = sharedInstance;if (cs == null) {// 使用同步块以确保线程安全Class var1 = DefaultConversionService.class;synchronized (DefaultConversionService.class) {cs = sharedInstance;if (cs == null) {cs = new DefaultConversionService(); // 初始化新实例sharedInstance = cs; // 更新共享实例}}}return cs; // 返回共享实例}/*** 向 ConverterRegistry 中添加默认的转换器。* 包括基本数据类型、集合类型、时区、以及一些特定的对象。*/public static void addDefaultConverters(ConverterRegistry converterRegistry) {addScalarConverters(converterRegistry); // 添加标量类型的转换器addCollectionConverters(converterRegistry); // 添加集合类型的转换器// 添加更多特定类型的转换器converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));converterRegistry.addConverter(new StringToTimeZoneConverter());converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());converterRegistry.addConverter(new ObjectToObjectConverter());converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));converterRegistry.addConverter(new FallbackObjectToStringConverter());converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));}/*** 添加集合类型的转换器,处理数组、集合、Map 等类型之间的转换。*/public static void addCollectionConverters(ConverterRegistry converterRegistry) {ConversionService conversionService = (ConversionService) converterRegistry;// 添加数组与集合之间的相互转换converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));converterRegistry.addConverter(new MapToMapConverter(conversionService));// 添加数组与字符串之间的转换converterRegistry.addConverter(new ArrayToStringConverter(conversionService));converterRegistry.addConverter(new StringToArrayConverter(conversionService));// 添加对象与数组/集合之间的转换converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));converterRegistry.addConverter(new CollectionToStringConverter(conversionService));converterRegistry.addConverter(new StringToCollectionConverter(conversionService));converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));// 添加 Stream 类型的转换器converterRegistry.addConverter(new StreamConverter(conversionService));}/*** 添加标量类型的转换器,处理数字、字符、布尔等基本数据类型的转换。*/private static void addScalarConverters(ConverterRegistry converterRegistry) {// 添加 Number 类型的转换工厂,支持数字类型间的转换converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());// 添加 String 到 Number 的转换工厂converterRegistry.addConverterFactory(new StringToNumberConverterFactory());// 添加数字到字符串的转换converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());// 添加 String 到 Character 的转换converterRegistry.addConverter(new StringToCharacterConverter());// 添加 Character 到 String 的转换converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());// 添加 Number 到 Character 的转换converterRegistry.addConverter(new NumberToCharacterConverter());// 添加 Character 到 Number 的转换工厂converterRegistry.addConverterFactory(new CharacterToNumberFactory());// 添加 String 到 Boolean 的转换converterRegistry.addConverter(new StringToBooleanConverter());// 添加 Boolean 到 String 的转换converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());// 添加 String 到 Enum 的转换工厂converterRegistry.addConverterFactory(new StringToEnumConverterFactory());// 添加 Enum 到 String 的转换converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));// 添加 Integer 到 Enum 的转换工厂converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());// 添加 Enum 到 Integer 的转换converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));// 添加 String 到 Locale 的转换converterRegistry.addConverter(new StringToLocaleConverter());// 添加 Locale 到 String 的转换converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());// 添加 String 到 Charset 的转换converterRegistry.addConverter(new StringToCharsetConverter());// 添加 Charset 到 String 的转换converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());// 添加 String 到 Currency 的转换converterRegistry.addConverter(new StringToCurrencyConverter());// 添加 Currency 到 String 的转换converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());// 添加 String 到 Properties 的转换converterRegistry.addConverter(new StringToPropertiesConverter());// 添加 Properties 到 String 的转换converterRegistry.addConverter(new PropertiesToStringConverter());// 添加 String 到 UUID 的转换converterRegistry.addConverter(new StringToUUIDConverter());// 添加 UUID 到 String 的转换converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());// 添加 String 到 Pattern 的转换converterRegistry.addConverter(new StringToPatternConverter());// 添加 Pattern 到 String 的转换converterRegistry.addConverter(Pattern.class, String.class, new ObjectToStringConverter());// 如果检测到 Kotlin 环境,添加 String 和 Regex 之间的转换if (KotlinDetector.isKotlinPresent()) {converterRegistry.addConverter(new StringToRegexConverter());converterRegistry.addConverter(Regex.class, String.class, new ObjectToStringConverter());}}
}
上述的代码,类似bean的管理:注册器管理着众多的转换器,为我们提供了一个转化服务。
其中addConverter
方法接收的是一个GenericConverter converter
类型的转换器;这个接口源码:
/*** 通用转换器接口,定义如何在源类型和目标类型之间进行转换*/
public interface GenericConverter {/*** 返回当前转换器支持的源类型和目标类型对的集合* @return 可转换的类型对集合,类型对通过 ConvertiblePair 表示*/@NullableSet<GenericConverter.ConvertiblePair> getConvertibleTypes();/*** 执行从源对象到目标类型的实际转换* @param source 源对象,可能为 null* @param sourceType 源对象的类型描述符* @param targetType 目标类型的描述符* @return 转换后的对象,可能为 null*/@NullableObject convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);/*** 内部类,用于封装一个源类型和目标类型的配对*/public static final class ConvertiblePair {private final Class<?> sourceType; // 源类型private final Class<?> targetType; // 目标类型/*** 构造函数,创建一个源类型和目标类型的配对* @param sourceType 源类型,不能为空* @param targetType 目标类型,不能为空*/public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {// 验证参数不为空Assert.notNull(sourceType, "Source type must not be null");Assert.notNull(targetType, "Target type must not be null");this.sourceType = sourceType;this.targetType = targetType;}/*** 获取源类型* @return 源类型的 Class 对象*/public Class<?> getSourceType() {return this.sourceType;}/*** 获取目标类型* @return 目标类型的 Class 对象*/public Class<?> getTargetType() {return this.targetType;}}
}
进一步我们查看GenericConverter
其中一个实现类StringToArrayConverter
的源码实现:
/*** StringToArrayConverter 是一个用于将字符串转换为数组的转换器实现,* 实现了 ConditionalGenericConverter 接口。它基于逗号分隔的字符串将其转换为目标数组类型。*/
final class StringToArrayConverter implements ConditionalGenericConverter {// ConversionService 用于处理具体的转换过程private final ConversionService conversionService;/*** 构造函数,接收一个 ConversionService 对象* @param conversionService 用于元素类型的进一步转换*/public StringToArrayConverter(ConversionService conversionService) {this.conversionService = conversionService;}/*** 返回该转换器支持的源类型和目标类型对* @return 只支持 String 到 Object[] 的转换*/public Set<ConvertiblePair> getConvertibleTypes() {return Collections.singleton(new ConvertiblePair(String.class, Object[].class));}/*** 判断是否能够匹配源类型和目标类型* @param sourceType 源类型的描述符* @param targetType 目标类型的描述符* @return 如果元素可以转换,则返回 true*/public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {// 检查元素是否可以转换return ConversionUtils.canConvertElements(sourceType, targetType.getElementTypeDescriptor(), this.conversionService);}/*** 将字符串源对象转换为目标数组类型* @param source 源对象,可能为 null* @param sourceType 源类型的描述符* @param targetType 目标类型的描述符* @return 转换后的目标数组对象,或者 null*/@Nullablepublic Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {if (source == null) {// 如果源对象为 null,则返回 nullreturn null;} else {// 将源对象强制转换为字符串String string = (String)source;// 使用逗号分隔字符串生成数组String[] fields = StringUtils.commaDelimitedListToStringArray(string);// 获取目标数组的元素类型描述符TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();// 确保目标元素类型不为 nullAssert.state(targetElementType != null, "No target element type");// 根据目标元素类型创建目标数组对象Object target = Array.newInstance(targetElementType.getType(), fields.length);// 遍历字符串字段数组,将每个字段转换为目标类型的元素for(int i = 0; i < fields.length; ++i) {String sourceElement = fields[i];// 去除字段的空格,并进行类型转换Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetElementType);// 将转换后的元素放入目标数组中Array.set(target, i, targetElement);}// 返回最终的目标数组对象return target;}}
}
接下来尝试写一个自己的converter
:
/*** TypeStringValueToIntegerConverter 类实现了 GenericConverter 接口,* 用于将 TypedStringValue 类型的对象转换为 Integer 类型的对象。*/
public class TypeStringValueToIntegerConverter implements GenericConverter {/*** 返回此转换器支持的源类型和目标类型对。* 在这里,转换器支持将 TypedStringValue 类型转换为 Integer 类型。* * @return 该转换器支持的 ConvertiblePair 集合*/@Overridepublic Set<ConvertiblePair> getConvertibleTypes() {// 返回一个包含源类型为 TypedStringValue,目标类型为 Integer 的 ConvertiblePairreturn Collections.singleton(new ConvertiblePair(TypedStringValue.class, Integer.class));}/*** 将给定的源对象从 TypedStringValue 转换为 Integer。* * @param source 源对象,期望是 TypedStringValue 类型* @param sourceType 源对象的类型描述符* @param targetType 目标类型的描述符* @return 转换后的 Integer 对象*/@Overridepublic Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {// 将源对象强制转换为 TypedStringValue 类型TypedStringValue typedStringValue = (TypedStringValue) source;// 使用 Integer 的 valueOf 方法将字符串值转换为 Integerreturn Integer.valueOf(typedStringValue.getValue());}
}
我们需要在批量构造的代码中,加上转化服务:
// 1. 通过任意形式捕获 beanDefinition
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(registry);// 从指定的 XML 配置文件加载 Bean 定义
xmlReader.loadBeanDefinitions("classpath:bean.xml");// 2. 通过反射实例化
String[] definitionNames = registry.getBeanDefinitionNames();// 遍历所有的 Bean 定义名称
for (String definitionName : definitionNames) {// 获取 BeanDefinition 对象BeanDefinition beanDefinition = registry.getBeanDefinition(definitionName);// 获取 Bean 的类名String beanClassName = beanDefinition.getBeanClassName();// 通过类名加载该类,返回 Class 对象Class<?> aClass = Class.forName(beanClassName);// 3. 使用 BeanWrapper 包裹实例,使其更方便使用反射方法BeanWrapper beanWrapper = new BeanWrapperImpl(aClass);// 4.需要自定义转化服务DefaultConversionService service = new DefaultConversionService();service.addConverter(new TypeStringValueToIntegerConverter());beanWrapper.setConversionService(service);// 设置属性值,将 BeanDefinition 中的属性值注入到 Bean 实例中beanWrapper.setPropertyValues(beanDefinition.getPropertyValues());// 获取实例化后的 Bean 对象Object bean = beanWrapper.getWrappedInstance();// 输出 Bean 对象的信息(取决于该类的 toString 方法)System.out.println(bean);
}
2、converter结构
接下来我们查看这个注册器的源码,通过converterRegistry.addConverter
追踪:
public void addConverter(GenericConverter converter) { this.converters.add(converter); this.invalidateCache();
}
这个this.converters
在代码中对应着一个对象:
private final GenericConversionService.Converters converters = new GenericConversionService.Converters();
查看Converters类:
/*** Converters 是一个内部静态类,主要用于管理和操作转换器(GenericConverter)的集合。* 它负责注册、移除、查找和匹配适当的转换器来处理不同类型之间的转换。*/
private static class Converters {// 全局转换器的集合,线程安全的集合类 CopyOnWriteArraySet 用于存储。private final Set<GenericConverter> globalConverters = new CopyOnWriteArraySet<>();// 用于存储具体的 ConvertiblePair 到 ConvertersForPair 的映射,初始容量为 256。private final Map<ConvertiblePair, GenericConversionService.ConvertersForPair> converters = new ConcurrentHashMap<>(256);// 私有构造函数,避免外部实例化private Converters() {}/*** 添加转换器到 converters 集合中。如果 ConvertibleTypes 为空,* 该转换器将被添加到全局转换器集中,否则添加到具体的可匹配的类型对。** @param converter 要添加的转换器*/public void add(GenericConverter converter) {Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();// 如果 convertibleTypes 为 null,断言该转换器必须是 ConditionalConverterif (convertibleTypes == null) {Assert.state(converter instanceof ConditionalConverter, "Only conditional converters may return null convertible types");this.globalConverters.add(converter); // 添加到全局转换器集合} else {// 遍历 ConvertiblePair 并添加到对应的匹配集合for (ConvertiblePair convertiblePair : convertibleTypes) {this.getMatchableConverters(convertiblePair).add(converter);}}}/*** 根据源类型和目标类型移除某个转换器。** @param sourceType 源类型* @param targetType 目标类型*/public void remove(Class<?> sourceType, Class<?> targetType) {this.converters.remove(new ConvertiblePair(sourceType, targetType));}/*** 查找与给定的源类型和目标类型相匹配的转换器。* 会从类的继承层次结构中依次查找匹配的转换器。** @param sourceType 源类型描述符* @param targetType 目标类型描述符* @return 匹配的转换器,如果没有找到则返回 null*/@Nullablepublic GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {// 获取源类型和目标类型的类层次结构List<Class<?>> sourceCandidates = this.getClassHierarchy(sourceType.getType());List<Class<?>> targetCandidates = this.getClassHierarchy(targetType.getType());// 遍历源类型和目标类型候选项进行匹配for (Class<?> sourceCandidate : sourceCandidates) {for (Class<?> targetCandidate : targetCandidates) {ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);GenericConverter converter = this.getRegisteredConverter(sourceType, targetType, convertiblePair);if (converter != null) {return converter; // 找到匹配的转换器}}}return null; // 未找到匹配的转换器}
}
其中converters
的结构如下图所示:
五、resource匹配
1、内置的Resource的实现
Spring框架包含了几种常用的Resource
实现类,用于访问不同类型的资源。以下是这些实现类的介绍:
- UrlResource:
- 用于封装
java.net.URL
对象,能够通过 URL 访问任何类型的资源,如文件、HTTPS目标、FTP目标等。 - 支持的 URL 前缀包括:
file:
访问本地文件系统路径https:
通过 HTTPS 协议访问资源ftp:
通过 FTP 协议访问资源
- 用于封装
- ClassPathResource:
- 用于从类路径(classpath)中获取资源。
- 使用线程上下文类加载器、给定的类加载器或类自身来加载资源,通常用于读取项目中的配置文件或类路径下的资源。
- FileSystemResource:
- 基于
java.io.File
的实现,用于操作系统文件系统中的文件资源。 - 可以直接访问本地文件系统上的文件。
- 基于
- InputStreamResource:
- 基于给定的
InputStream
对象的资源实现。 - 适用于没有具体资源实现时的情况,如从网络连接或其他来源获取的流对象。
- 基于给定的
- ByteArrayResource:
- 使用给定的字节数组作为数据源的资源实现。
- 通常用于需要通过内存中的字节数组来处理数据的场景。
这些内置的 Resource
实现为 Spring 提供了灵活的资源访问方式,能够处理不同来源的文件和数据资源。
下面是三个测试用例的实现示例,使用了 Spring 框架的 Resource
实现类和 commons-io
工具包来进行资源的读写操作。
测试用例 1:测试 UrlResource
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;import java.io.FileOutputStream;
import java.io.IOException;public class ResourceTest {@Testpublic void testUrlResource() throws IOException {// 创建一个UrlResource对象,用于下载资源Resource resource = new UrlResource("https://d1dir1.qq.com/qqfile/qq/PCQQ9.7.0/QQ9.7.0.28921.exe");// 使用 FileOutputStream 将下载的文件保存到本地路径 D://FileOutputStream fos = new FileOutputStream("D://"+resource.getFilename());// 使用 commons-io 工具包将资源输入流复制到本地输出流IOUtils.copy(resource.getInputStream(), fos);// 关闭流fos.close();}
}
测试用例 2:测试 FileSystemResource
:
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;import java.io.IOException;public class ResourceTest {@Testpublic void testFileSystemResource() throws IOException {// 创建 FileSystemResource 对象,指向文件系统中的某个文件Resource resource = new FileSystemResource("D:/spring/spring.xml");// 创建缓冲区读取数据byte[] buffer = new byte[1024 * 100];int offset = IOUtils.read(resource.getInputStream(), buffer);// 打印读取到的数据System.out.println(new String(buffer, 0, offset));}
}
测试用例 3:测试 ClassPathResource
:
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;import java.io.IOException;public class ResourceTest {@Testpublic void testClassPathResource() throws IOException {// 创建 ClassPathResource 对象,从类路径中加载资源Resource resource = new ClassPathResource("spring.xml");// 创建缓冲区读取数据byte[] buffer = new byte[1024 * 100];int offset = IOUtils.read(resource.getInputStream(), buffer);// 打印读取到的数据System.out.println(new String(buffer, 0, offset));}
}
PathMatchingResourcePatternResolver
是 Spring 框架中用于加载资源的实用类,支持通过路径模式匹配加载资源。
getResource(location)
用于获取单个资源。getResources(locationPattern)
可以使用通配符匹配来获取多个资源。
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;public class ResourceLoaderExample {public static void main(String[] args) throws Exception {PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();// 加载单个网络资源Resource resource = resolver.getResource("https://dldir1.qq.com/qqfile/qq/PCQQ9.7.1/QQ9.7.1.exe");System.out.println("Resource URI: " + resource.getURI());// 加载类路径中的 XML 文件Resource xmlResource = resolver.getResource("classpath:bean.xml");System.out.println("XML Resource URI: " + xmlResource.getURI());// 加载匹配 classpath 的多个资源Resource[] resources = resolver.getResources("classpath*:META-INF/spring.factories");for (Resource res : resources) {System.out.println("Resource URI: " + res.getURI());}}
}
2、加载xml
回到之前的代码:
// 创建一个 BeanDefinitionRegistry 实例,用于保存和管理 Bean 定义
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();// 创建一个 XmlBeanDefinitionReader 实例,并将其与 BeanDefinitionRegistry 关联
// XmlBeanDefinitionReader 负责从 XML 文件中读取 Bean 的定义,并将其注册到指定的 BeanDefinitionRegistry 中
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(registry);// 从指定的 XML 配置文件中加载 Bean 定义
// 这里指定的文件路径为 "classpath:bean.xml",表示文件位于类路径中
// XmlBeanDefinitionReader 会解析该文件中的所有 Bean 定义并将它们注册到 registry 中
xmlReader.loadBeanDefinitions("classpath:bean.xml");
查看loadBeanDefinitions
源码:
// 加载指定位置的 Bean 定义
// location: Bean 配置文件的路径
// actualResources: 用来存储加载成功的资源 (Resource) 对象,可能为 null
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {// 获取资源加载器ResourceLoader resourceLoader = this.getResourceLoader();// 如果没有可用的 ResourceLoader,则抛出异常if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");} else {int count;// 如果 ResourceLoader 是 ResourcePatternResolver 的实例(支持路径模式匹配),则使用它来加载资源if (resourceLoader instanceof ResourcePatternResolver) {ResourcePatternResolver resourcePatternResolver = (ResourcePatternResolver) resourceLoader;try {// 使用资源模式解析器获取符合 location 路径模式的所有资源Resource[] resources = resourcePatternResolver.getResources(location);// 调用 loadBeanDefinitions(Resource[]) 方法加载这些资源中的 Bean 定义count = this.loadBeanDefinitions(resources);// 如果 actualResources 不为 null,则将所有成功加载的资源添加到 actualResources 集合中if (actualResources != null) {Collections.addAll(actualResources, resources);}// 如果日志级别为 TRACE,则记录加载的 Bean 定义数量和位置if (this.logger.isTraceEnabled()) {this.logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");}return count;} catch (IOException var7) {// 捕获 IO 异常并抛出 BeanDefinitionStoreException,表示资源模式解析时发生错误throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var7);}} else {// 如果 ResourceLoader 不是 ResourcePatternResolver 实例,则直接通过它加载单个资源Resource resource = resourceLoader.getResource(location);// 调用 loadBeanDefinitions(Resource) 方法加载该资源中的 Bean 定义count = this.loadBeanDefinitions((Resource) resource);// 如果 actualResources 不为 null,则将加载的资源添加到 actualResources 集合中if (actualResources != null) {actualResources.add(resource);}// 如果日志级别为 TRACE,则记录加载的 Bean 定义数量和位置if (this.logger.isTraceEnabled()) {this.logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");}return count;}}
}
其中比较关键的两行:
Resource[] resources = resourcePatternResolver.getResources(location);// 调用 loadBeanDefinitions(Resource[]) 方法加载这些资源中的 Bean 定义
count = this.loadBeanDefinitions(resources);
getResources
即使用上小节的通配匹配获取资源;接下来查看核心函数loadBeanDefinitions
:
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int count = 0; Resource[] var3 = resources; int var4 = resources.length; for(int var5 = 0; var5 < var4; ++var5) { Resource resource = var3[var5]; count += this.loadBeanDefinitions((Resource)resource); } return count;
}
继续深入:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {// 检查传入的 EncodedResource 是否为空,如果为空则抛出异常Assert.notNull(encodedResource, "EncodedResource must not be null");// 如果日志级别为 TRACE,记录日志,表示正在从 encodedResource 加载 XML Bean 定义if (this.logger.isTraceEnabled()) {this.logger.trace("Loading XML bean definitions from " + encodedResource);}// 获取当前正在加载的资源集合,确保不会出现循环加载Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();// 如果当前资源已经在加载集合中,则抛出异常,防止循环引用(即 XML 配置文件相互导入导致的无限递归)if (!currentResources.add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");} else {int var5;try {// 获取资源的输入流InputStream inputStream = encodedResource.getResource().getInputStream();try {// 创建 InputSource 对象,用于解析 XML 文件InputSource inputSource = new InputSource(inputStream);// 如果有指定的编码格式,则设置到 InputSource 中if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}// 调用核心方法 doLoadBeanDefinitions,解析 XML 并加载 Bean 定义var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());} catch (Throwable var12) {// 在解析 XML 过程中出现异常时,关闭输入流并抛出异常if (inputStream != null) {try {inputStream.close();} catch (Throwable var11) {// 如果关闭输入流时出错,将错误附加到原始异常中var12.addSuppressed(var11);}}throw var12;}// 确保在正常解析结束后关闭输入流if (inputStream != null) {inputStream.close();}} catch (IOException var13) {// 捕获 IO 异常,并抛出 BeanDefinitionStoreException,指明加载 XML 资源时出现 IO 错误throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var13);} finally {// 在 finally 块中,无论是否成功,都会移除当前加载的资源,防止内存泄漏currentResources.remove(encodedResource);// 如果当前资源集合为空,则移除该线程局部变量if (currentResources.isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();}}// 返回加载的 Bean 定义数量return var5;}
}
核心方法:var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {try {// 调用 doLoadDocument 方法,将传入的 InputSource 和 Resource 转换为 Document 对象 (XML文档)Document doc = this.doLoadDocument(inputSource, resource);// 调用 registerBeanDefinitions 方法,将解析出的 Document 注册为 Bean 定义,返回已注册的 Bean 定义数量int count = this.registerBeanDefinitions(doc, resource);// 如果日志级别为 DEBUG,则记录已加载的 Bean 定义数量以及来源的资源信息if (this.logger.isDebugEnabled()) {this.logger.debug("Loaded " + count + " bean definitions from " + resource);}// 返回加载的 Bean 定义数量return count;} catch (BeanDefinitionStoreException var5) {// 如果抛出 BeanDefinitionStoreException,则直接重新抛出该异常throw var5;} catch (SAXParseException var6) {// 如果在解析 XML 文档时出现 SAX 解析异常,并且包含行号信息,抛出一个带有更详细错误信息的 XmlBeanDefinitionStoreExceptionthrow new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var6.getLineNumber() + " in XML document from " + resource + " is invalid", var6);} catch (SAXException var7) {// 如果在解析 XML 过程中出现其他 SAX 异常,抛出 XmlBeanDefinitionStoreException,提示 XML 文档无效throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var7);} catch (ParserConfigurationException var8) {// 如果出现解析器配置异常,抛出 BeanDefinitionStoreException,提示解析器配置错误throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var8);} catch (IOException var9) {// 如果在解析过程中出现 IO 异常,抛出 BeanDefinitionStoreException,提示 IO 错误throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var9);} catch (Throwable var10) {// 捕获所有其他未预料的异常,抛出 BeanDefinitionStoreException,提示解析过程中发生了意外的异常throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var10);}
}
六、环境
Spring 提供的 Environment
接口是对应用程序运行环境的抽象,主要模拟了应用程序的两个核心部分:profiles 和 properties。这些功能帮助应用程序根据不同的环境条件或配置需求,动态地管理 bean 定义和应用程序的配置。
1. Profiles(配置分组)
- Profile 是一种用于对 bean 定义进行分组的机制。我们可以根据应用程序的不同运行环境(如开发、测试、生产等)定义不同的 profile。
- 一个 profile 包含一组特定的 bean 定义,这些 bean 只有在该 profile 被激活时才会被加载到 Spring 容器中。这种机制允许我们根据环境条件灵活地选择和加载不同的配置。
激活 profile 的方式:
- 在
application.properties
或application.yml
文件中指定:
spring.profiles.active=dev
- 通过 JVM 启动参数指定:
-Dspring.profiles.active=prod
- 编程方式动态设置:
`ConfigurableEnvironment environment = applicationContext.getEnvironment(); environment.setActiveProfiles("test");`
2. Properties(属性配置)
- Properties 是应用程序中的一个重要概念,通常以 key-value 的形式存在,用来配置应用的各种参数。
- 属性可以来自多种不同的来源,包括:
- 属性文件(如
.properties
或.yaml
文件) - JVM 系统属性(如
-D
参数) - 系统环境变量
- JNDI 属性
- servlet 上下文参数
- 自定义的
Properties
对象或Map
对象
- 属性文件(如
Spring 通过 Environment
对象为这些属性源提供了统一的访问接口。你可以通过 Environment
接口来获取这些属性,并应用到应用程序的不同部分。
获取属性的方式:
- 使用
Environment
提供的getProperty()
方法来解析属性:
Environment env = applicationContext.getEnvironment();
String dbUrl = env.getProperty("database.url");
- 这种机制允许我们通过配置文件、环境变量等多种途径设置应用程序属性,并通过代码动态解析它们,从而大大增强了应用程序的可配置性和灵活性。
spring中尝试获取上下文环境,并输出环境变量:
// 创建一个通用的ApplicationContext容器
//创建一个通用的 `ApplicationContext` 实例,它是 Spring 框架的核心容器,负责加载和管理 beans。
ApplicationContext ctx = new GenericApplicationContext();// 获取当前应用程序环境的Environment对象
// Environment提供了一系列方法,用于访问系统属性、环境变量和配置文件中的属性
Environment env = ctx.getEnvironment();// 使用Environment对象的containsProperty()方法检查名为"JAVA_HOME"的属性是否存在
// "JAVA_HOME"通常是用于指定Java安装路径的环境变量
boolean containsMyProperty = env.containsProperty("JAVA_HOME");// 通过Logger记录信息,输出是否存在名为"JAVA_HOME"的环境变量
// {}是占位符,后面的containsMyProperty值(true或false)会动态替换进去
Logger.info("Does my environment contain the 'JAVA_HOME' property? {}", containsMyProperty);// 使用getProperty()方法获取"JAVA_HOME"属性的值
// 如果存在这个属性,它会返回实际值;如果不存在,返回null
Logger.info("The 'JAVA_HOME' is {}", env.getProperty("JAVA_HOME"));
这里的Environment
的具体实现类是StandardEnvironment
,我们自己尝试一下创建一个StandardEnvironment
并添加属性:
// 创建一个 StandardEnvironment 实例,这是 Spring 的标准环境实现,包含系统环境变量和 JVM 属性等信息
StandardEnvironment env = new StandardEnvironment();// 创建一个 Properties 对象,用于存储键值对形式的配置信息
Properties properties = new Properties();
properties.setProperty("age", "12"); // 设置键 "age" 的值为 "12"// 将 Properties 对象封装为一个 PropertySource 对象,
// 其中 name 为 "my-propertySource",表示属性源的名字,第二个参数是 properties 对象
PropertySource<?> source = new PropertiesPropertySource("my-propertySource", properties);// 获取当前环境对象的 PropertySources 集合,
// 这是一个可变的属性源集合,包含所有环境配置的属性源
MutablePropertySources propertySources = env.getPropertySources();// 将我们创建的 PropertySource 添加到属性源集合的最后(addLast 表示追加到最后)
propertySources.addLast(source);// 打印出在环境中查找属性 "age" 的值,应该输出 "12"
System.out.println(env.getProperty("age")); // 输出: 12
@PropertySource
注解提供了一种声明性方式,可以将属性文件中的键值对添加到 Spring 环境(Environment
)中。你可以通过这个注解将属性文件加载到 Spring 的上下文中,以便在应用程序中使用这些属性。
假设有一个名为 app.properties
的文件,内容如下:
teacherName=itnanls
编写配置类:
@Configuration
@PropertySource("classpath:app.properties") // 加载类路径下的 app.properties 文件
public class AppConfiguration {// 这里可以定义更多的配置内容或 Bean
}
测试类:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import static org.junit.jupiter.api.Assertions.assertEquals;@SpringBootTest(classes = AppConfiguration.class) // 指定 Spring Boot 测试环境,加载 AppConfiguration 类
public class PropertySourceTest {@AutowiredEnvironment environment; // 注入 Spring 的 Environment,用于访问属性@Testpublic void testEnv() {// 从 Environment 中获取 "teacherName" 属性的值,并输出到控制台String teacherName = environment.getProperty("teacherName");System.out.println(teacherName);// 断言属性值是否为 "itnanls"assertEquals("itnanls", teacherName);}
}
七、发布订阅
1. 概述
Spring 提供的 事件多播器(Event Multicaster),是一种实现发布-订阅模式的机制。它能够帮助开发者在应用程序中轻松地广播事件,使得事件可以被多个监听器接收并处理。这种模式与组播(multicast)类似,即消息只会在需要时复制,确保消息传递的效率。
在 Spring 框架中,事件机制是基于观察者设计模式实现的。通过使用 SimpleApplicationEventMulticaster
,我们可以轻松地发布事件并注册监听器,响应这些事件。这种机制适用于事件驱动的开发方式,可以让组件之间解耦,同时确保各个监听器能独立地处理事件。
实现监听器:
import org.springframework.context.ApplicationListener;public class EmailListener implements ApplicationListener<OrderEvent> {@Overridepublic void onApplicationEvent(OrderEvent event) {// 处理事件,例如发送邮件System.out.println("Email sent form: " + event.getSource());}
}public class MessageListener implements ApplicationListener<OrderEvent> {@Overridepublic void onApplicationEvent(OrderEvent event) {// 处理事件,例如发送消息System.out.println("Message sent form: " + event.getSource());}
}
定义事件类:
import org.springframework.context.ApplicationEvent;public class OrderEvent extends ApplicationEvent {public OrderEvent(Object source) {super(source);}@Overridepublic String toString() {return "OrderEvent triggered!";}
}
测试方法:
@Test
public void testEventMulticaster() {// 创建一个简单的事件多播器 SimpleApplicationEventMulticaster 实例SimpleApplicationEventMulticaster caster = new SimpleApplicationEventMulticaster();// 为事件多播器添加监听器,这些监听器将会处理事件caster.addApplicationListener(new EmailListener()); // 添加 EmailListenercaster.addApplicationListener(new MessageListener()); // 添加 MessageListener// 模拟触发事件,向所有注册的监听器广播一个 OrderEvent 事件caster.multicastEvent(new OrderEvent(this)); // `this` 代表事件源
}
2. 源码阅读
这其中有很多复杂的情况,比如listener
是我们直接手动注册的实例呢,还是spring工厂 中的bean呢,如果是bean是singleton
还是prototype
呢?
因为源码比较复杂,我们需要结合下图一起看:
(即发布了事件要进行实例化的过程)
当listener
被调用执行后,如何进行了缓存:
Spring 的事件多播器在广播事件时,会缓存已解析的事件类型和监听器列表,以加速重复事件的广播。spring提供了一个retrieverCache
缓存,其key
是[Event+Source]
,value
是已解析的监听器列表,其中单例、非单例、编程式的分别进行存储:
- 编程式的
listener
和单例的listener bean
存储在一起 - 非单例的
bean
存储在一个集合中
查看addApplicationListener
源码:
public void addApplicationListener(ApplicationListener<?> listener) {// 使用 synchronized 关键字对 defaultRetriever 进行同步,以确保线程安全synchronized(this.defaultRetriever) {// 尝试获取 listener 的单例目标对象Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);// 如果 singletonTarget 是 ApplicationListener 的实例if (singletonTarget instanceof ApplicationListener) {// 从 applicationListeners 列表中移除 singletonTarget,以防重复添加this.defaultRetriever.applicationListeners.remove(singletonTarget);}// 将 listener 添加到 applicationListeners 列表中this.defaultRetriever.applicationListeners.add(listener);// 清空 retrieverCache 缓存,确保新的监听器配置能及时生效this.retrieverCache.clear();}
}
查看其核心方法this.defaultRetriever.applicationListeners.add(listener);
:
查看this.defaultRetriever
的相关代码:
private class DefaultListenerRetriever {// 用于存储已注册的 ApplicationListener 实例的集合,确保唯一性和顺序public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();// 用于存储监听器的 Bean 名称,延迟加载这些 Beanpublic final Set<String> applicationListenerBeans = new LinkedHashSet<>();// 私有构造函数,限制实例化方式private DefaultListenerRetriever() {}/*** 获取所有注册的 ApplicationListener 实例,包括直接注册的监听器实例和通过 bean 名称注册的监听器。* @return 返回 ApplicationListener 实例的集合,按照顺序和优先级排列。*/public Collection<ApplicationListener<?>> getApplicationListeners() {// 创建一个列表,用于存放所有的监听器,大小为已注册的实例数量与 Bean 名称数量之和List<ApplicationListener<?>> allListeners = new ArrayList<>(this.applicationListeners.size() + this.applicationListenerBeans.size());// 将直接添加的监听器实例加入到 allListeners 列表中allListeners.addAll(this.applicationListeners);// 如果 applicationListenerBeans 不为空,说明存在通过 Bean 名称注册的监听器if (!this.applicationListenerBeans.isEmpty()) {// 获取 BeanFactory,以便通过 Bean 名称加载监听器实例BeanFactory beanFactory = AbstractApplicationEventMulticaster.this.getBeanFactory();// 遍历 applicationListenerBeans 集合Iterator<String> var3 = this.applicationListenerBeans.iterator();while(var3.hasNext()) {String listenerBeanName = var3.next();try {// 根据 Bean 名称获取 ApplicationListener 实例ApplicationListener<?> listener = (ApplicationListener<?>) beanFactory.getBean(listenerBeanName, ApplicationListener.class);// 如果该监听器不在 allListeners 列表中,则添加,避免重复if (!allListeners.contains(listener)) {allListeners.add(listener);}} catch (NoSuchBeanDefinitionException var6) {// 捕获 NoSuchBeanDefinitionException 异常,若该 Bean 名称不存在则忽略}}}// 使用 AnnotationAwareOrderComparator 对所有监听器进行排序,确保监听器按优先级顺序执行AnnotationAwareOrderComparator.sort(allListeners);// 返回包含所有监听器的集合return allListeners;}
}
接下来注册事件multicastEvent
的源码:
public void multicastEvent(ApplicationEvent event) {// 调用重载方法 multicastEvent,传入 event 和 null,null 表示使用事件默认的类型this.multicastEvent(event, (ResolvableType)null);
}public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {// 如果 eventType 不为空,使用 eventType;否则根据事件实例确定事件类型ResolvableType type = eventType != null ? eventType : ResolvableType.forInstance(event);// 获取任务执行器,用于异步执行监听器方法Executor executor = this.getTaskExecutor();// 获取与事件类型匹配的监听器,并进行迭代Iterator<ApplicationListener<?>> var5 = this.getApplicationListeners(event, type).iterator();// 循环遍历所有监听器,依次调用它们while(var5.hasNext()) {// 获取当前监听器ApplicationListener<?> listener = var5.next();// 如果存在执行器且监听器支持异步执行if (executor != null && listener.supportsAsyncExecution()) {try {// 使用执行器异步调用监听器的处理方法executor.execute(() -> {this.invokeListener(listener, event);});} catch (RejectedExecutionException var8) {// 如果任务被拒绝(执行器可能满载),则直接同步执行监听器this.invokeListener(listener, event);}} else {// 如果执行器不可用或监听器不支持异步执行,则同步调用监听器this.invokeListener(listener, event);}}
}
再往invokeListener
去细看,最后其实就是调用listener.onApplicationEvent(event);
方法
但我们更关注其缓存的过程,因此回到multicastEvent
方法中的获取监听器方法getApplicationListeners(event, type)
:
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {// 获取事件的来源对象Object source = event.getSource();// 获取来源对象的类型(如果来源对象不为空)Class<?> sourceType = source != null ? source.getClass() : null;// 创建一个监听器缓存键,用于缓存监听器的查询结果,缓存键包含事件类型和来源类型(Key)AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);// 用于存储新创建的缓存检索器(Value)AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;// 从缓存中获取已有的缓存检索器AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey);// 如果缓存中没有找到对应的检索器,并且类型信息是安全的(可缓存)if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {// 创建一个新的 CachedListenerRetriever,用于缓存该事件的监听器集合newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();// 尝试将新创建的缓存检索器放入缓存中,如果已经有相同键的缓存检索器则返回已有检索器existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);// 如果 existingRetriever 不为空,说明缓存中已有同键的缓存检索器,将 newRetriever 置为空if (existingRetriever != null) {newRetriever = null;}}// 如果 existingRetriever 不为空且其缓存的监听器集合存在,直接返回该集合if (existingRetriever != null) {Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();if (result != null) {return result;}}// 如果缓存中没有结果,调用 retrieveApplicationListeners 方法检索并返回事件监听器集合return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
查看兜底方法this.retrieveApplicationListeners(eventType, sourceType, newRetriever)
:
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {// 创建一个列表 allListeners,用于存储所有符合条件的监听器List<ApplicationListener<?>> allListeners = new ArrayList<>();// 如果 retriever 不为空,创建一个过滤后的监听器集合,用于后续缓存Set<ApplicationListener<?>> filteredListeners = retriever != null ? new LinkedHashSet<>() : null;// 同样为 retriever 创建一个过滤后的监听器 Bean 集合,用于后续缓存Set<String> filteredListenerBeans = retriever != null ? new LinkedHashSet<>() : null;LinkedHashSet<ApplicationListener<?>> listeners;LinkedHashSet<String> listenerBeans;// 从默认检索器 defaultRetriever 中获取所有监听器和监听器 Beansynchronized(this.defaultRetriever) {listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);}// 遍历所有的监听器对象Iterator<ApplicationListener<?>> var9 = listeners.iterator();while (var9.hasNext()) {ApplicationListener<?> listener = var9.next();// 检查当前监听器是否支持当前事件类型和来源类型if (this.supportsEvent(listener, eventType, sourceType)) {// 如果 retriever 不为空,将支持的监听器加入过滤后的监听器集合if (retriever != null) {filteredListeners.add(listener);}// 将支持的监听器加入到总的监听器列表allListeners.add(listener);}}// 如果存在监听器 Beanif (!listenerBeans.isEmpty()) {// 获取 Spring 的 BeanFactory 实例ConfigurableBeanFactory beanFactory = this.getBeanFactory();Iterator<String> var17 = listenerBeans.iterator();while (var17.hasNext()) {String listenerBeanName = var17.next();try {// 检查当前监听器 Bean 是否支持当前事件类型if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) {// 获取该监听器 Bean 的实例ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);// 获取监听器的原始对象(用于处理代理对象)ApplicationListener<?> unwrappedListener = (ApplicationListener<?>) AopProxyUtils.getSingletonTarget(listener);// 如果监听器是代理对象且其原始对象存在于缓存中,将原始对象替换为代理对象if (listener != unwrappedListener) {if (filteredListeners != null && filteredListeners.contains(unwrappedListener)) {filteredListeners.remove(unwrappedListener);filteredListeners.add(listener);}if (allListeners.contains(unwrappedListener)) {allListeners.remove(unwrappedListener);allListeners.add(listener);}}// 如果该监听器不在总的监听器列表中,并且支持当前事件类型,添加到相应集合中if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {// 如果 Bean 是单例,将其放入 filteredListeners,否则放入 filteredListenerBeansif (beanFactory.isSingleton(listenerBeanName)) {filteredListeners.add(listener);} else {filteredListenerBeans.add(listenerBeanName);}}allListeners.add(listener);}} else {// 如果不支持当前事件类型,从缓存和总监听器列表中移除Object listener = beanFactory.getSingleton(listenerBeanName);if (retriever != null) {filteredListeners.remove(listener);}allListeners.remove(listener);}} catch (NoSuchBeanDefinitionException var14) {// 捕获没有定义该 Bean 的异常,跳过当前 Bean}}}// 对总的监听器列表进行排序,确保监听器的执行顺序AnnotationAwareOrderComparator.sort(allListeners);// 如果 retriever 不为空,将过滤后的结果保存到缓存中if (retriever != null) {if (filteredListenerBeans.isEmpty()) {retriever.applicationListeners = new LinkedHashSet<>(allListeners);retriever.applicationListenerBeans = filteredListenerBeans;} else {retriever.applicationListeners = filteredListeners;retriever.applicationListenerBeans = filteredListenerBeans;}}// 返回所有支持的监听器集合return allListeners;
}
第三章 容器和上下文
使用容器的优势主要包括以下几个方面:
-
统一管理
使用容器需要遵循统一的规范,例如 Jakarta Servlet 6.0 规范、Spring 6 规范等。这些规范帮助我们编写标准化的容器内容(如 servlet、bean),便于统一管理容器内内容的生命周期。规范化的管理可以确保组件之间的兼容性和稳定性,减少维护成本。 -
隔离应用
容器可以隔离应用程序与底层复杂性,使开发者能够专注于业务逻辑的开发。理论上,我们不需要关心容器是如何启动的,如何建立连接等细节。容器封装了这些底层实现,开发者可以将更多的精力投入到实际的业务实现上,而无需关注底层技术实现。 -
分层管理
容器的设计通常分层清晰,每个层次有明确的职责划分。例如,MVC 框架中的容器与 Spring 的容器是不同的,但它们之间又能相互关联。这样的分层设计保证了职责的分离,使各层之间的边界清晰,便于管理和扩展,提升了系统的可维护性和模块化程度。
一、认识bean工厂
bean工厂是我们spring容器的载体, 是spring 上下文的主要内容。下图展示了我们整个beanI厂的常见的接口和类以及功能,其中我们需要注意几点:
- 不同的接口展现了不同的能力,是对子类能力的抽象
- 抽象类构建通用方法的实现,是通用核心方法(模板方法)的具体实现
- 具体类完成特定功能的实现,是特定功能的具体实现
有了这样的思想,我们才能更好的区阅读源码:
- ListablebeanFactory接口:更强的枚举能力
- AutowireCapableBeanFactory接口:自动装配的能力
- HierachiclBeanFactory接口:分层的能力
以上三个接口可组成一个复合接口:ConfigurableListableBeanFactory接口
1、基础能力
public interface BeanFactory {// 定义一个工厂Bean的前缀常量,通常用于区分FactoryBean类型的实例String FACTORY_BEAN_PREFIX = "&";// 根据Bean名称获取Bean实例Object getBean(String var1) throws BeansException;// 根据Bean名称和类型获取Bean实例<T> T getBean(String var1, Class<T> var2) throws BeansException;// 根据Bean名称和构造参数获取Bean实例Object getBean(String var1, Object... var2) throws BeansException;// 根据类型获取Bean实例<T> T getBean(Class<T> var1) throws BeansException;// 根据类型和构造参数获取Bean实例<T> T getBean(Class<T> var1, Object... var2) throws BeansException;// 获取Bean的ObjectProvider,用于延迟获取Bean实例<T> ObjectProvider<T> getBeanProvider(Class<T> var1);// 根据ResolvableType获取Bean的ObjectProvider<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);// 检查容器中是否包含指定名称的Beanboolean containsBean(String var1);// 判断Bean是否为单例模式boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;// 判断Bean是否为原型模式(即每次请求都会创建新实例)boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;// 判断Bean的类型是否匹配指定的ResolvableTypeboolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;// 判断Bean的类型是否匹配指定的Class类型boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;// 获取指定Bean的类型(返回Class对象),如果Bean不存在则返回null@NullableClass<?> getType(String var1) throws NoSuchBeanDefinitionException;// 获取指定Bean的类型,并指定是否初始化FactoryBean的实现类@NullableClass<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;// 获取指定Bean名称的所有别名String[] getAliases(String var1);
}
上面源码有提到ObjectProvider
,什么是ObjectProvider
?
ObjectProvider
继承自ObjectFactory
@FunctionalInterface
public interface ObjectFactory<T> {/**这个方法用于创建并返回对象。*如果在创建过程中出现问题(例如无法创建对象),会抛出 BeansException异常。**/T getObject() throws BeansException;
}
ObjectFactory
目的就是为了屏蔽复杂逻辑,直接创建对象。
如:
ObjectFactory<User> factory = () -> {// 通过某种逻辑生成 User,甚至可以生成代理对象return new Random().nextInt(100) > 50 ? new User("tom", 12) : new User("alice", 25);
};
但我们在获取时,不用关注具体逻辑。直接User user = factory.getObject();
获取即可
查看ObjectProvider
源码:
public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {// 获取容器中的一个对象实例,支持传入额外的参数进行构造函数注入T getObject(Object... var1) throws BeansException;// 如果容器中有可用的对象,返回该对象;如果没有,返回 null@NullableT getIfAvailable() throws BeansException;…………// 获取容器中唯一的对象实例,如果有多个符合条件的 Bean,返回 null@NullableT getIfUnique() throws BeansException;…………
}
ObjectProvider
允许 Spring 用户在运行时动态获取 Bean,并且可以选择性地提供默认值或者执行某些操作。它为按需获取和条件判断提供了多种方法,是 Spring 的灵活依赖注入的一部分。
小插曲:
ObjectProvider是为了解决隐式注入时产生的问题而提出的概念
spring4.3之前,我们的bean如果需要使用特定构造器进行构造时必须使用@Autowired注解
在 Spring 中,通常通过构造函数注入来传递依赖项:
@Service
public class UserService {private UserDao userDao;@Autowiredpublic UserService(UserDao userDao) {this.userDao = userDao;}
}
在上面的代码中,UserService
依赖于 UserDao
,并通过构造函数注入 UserDao
实例。在 Spring 容器启动时,UserDao
,否则会抛出 NoSuchBeanDefinitionException
。
当 Spring 容器中没有 UserDao
的实例,或者有多个 UserDao
实例时,构造函数注入将会失败,抛出类似以下的异常:
Parameter 0 of constructor in com.yd1class.UserService required a bean of type 'com.yd1class.UserDao' that could not be found.
ObjectProvider
可以用来处理可选的或唯一的 Bean 依赖。在这种情况下,如果 UserDao
不可用或不唯一,ObjectProvider
会提供一个懒加载的方式来获取 UserDao
,并能够优雅地处理这种情况。
@Service
public class UserService {private UserDao userDao;public UserService(ObjectProvider<UserDao> userDao) {// 使用 getIfAvailable() 或 getIfUnique() 来获取 UserDao 实例this.userDao = userDao.getIfUnique();}
}
在这个例子中,ObjectProvider<UserDao>
用于替代直接注入 UserDao
。ObjectProvider
提供了多种方法来处理 Bean 的获取:
getIfAvailable()
:如果容器中有UserDao
实例且没有冲突,则返回它。如果没有实例,则返回null
。getIfUnique()
:如果容器中有唯一的UserDao
实例,则返回它。如果存在多个实例,则返回null
2、更强大的枚举能力
public interface ListableBeanFactory extends BeanFactory {// 判断是否包含指定名称的Bean定义boolean containsBeanDefinition(String var1);// 获取Bean定义的数量int getBeanDefinitionCount();// 获取所有Bean定义的名称String[] getBeanDefinitionNames();// 获取指定类型的Bean的ObjectProvider,可选择包含非单例或懒加载的Bean<T> ObjectProvider<T> getBeanProvider(Class<T> var1, boolean var2);// 根据ResolvableType获取指定类型的Bean的ObjectProvider,可选择包含非单例或懒加载的Bean<T> ObjectProvider<T> getBeanProvider(ResolvableType var1, boolean var2);// 根据ResolvableType获取指定类型的Bean名称数组String[] getBeanNamesForType(ResolvableType var1);// 根据ResolvableType获取指定类型的Bean名称数组,可选择是否包含非单例或懒加载的BeanString[] getBeanNamesForType(ResolvableType var1, boolean var2, boolean var3);// 获取指定类型的Bean名称数组(通过Class类型)String[] getBeanNamesForType(@Nullable Class<?> var1);// 获取指定类型的Bean名称数组,可选择是否包含非单例或懒加载的Bean(通过Class类型)String[] getBeanNamesForType(@Nullable Class<?> var1, boolean var2, boolean var3);// 获取指定类型的所有Bean实例及其名称,返回Map<T> Map<String, T> getBeansOfType(@Nullable Class<T> var1) throws BeansException;// 获取指定类型的所有Bean实例及其名称,可选择是否包含非单例或懒加载的Bean,返回Map<T> Map<String, T> getBeansOfType(@Nullable Class<T> var1, boolean var2, boolean var3) throws BeansException;// 获取带有指定注解类型的Bean名称数组String[] getBeanNamesForAnnotation(Class<? extends Annotation> var1);// 获取带有指定注解类型的所有Bean实例及其名称,返回MapMap<String, Object> getBeansWithAnnotation(Class<? extends Annotation> var1) throws BeansException;// 在指定的Bean上查找指定类型的注解@Nullable<A extends Annotation> A findAnnotationOnBean(String var1, Class<A> var2) throws NoSuchBeanDefinitionException;
}
3、灵活的分层能力
分层的能力十分重要,这在web工程里有典型应用,spring和springmvc会建 立两个独立的上下文,后续涉及web工程时我们再深入讲解,分层之后各司其职,更易管理:
public interface HierarchicalBeanFactory extends BeanFactory {// 获取父级的BeanFactory,如果存在的话@NullableBeanFactory getParentBeanFactory();// 忽略祖先上下文定义的bean,检查本地工厂中是否包含指定名称的本地Bean定义boolean containsLocalBean(String var1);
}
4、构建和自动装配的能力
这个接口的实现及其复杂,主要是赋予子类自动装配的能力,是容器最核心的接口,这个接口定义了bean的创建以及装配能力,同时细粒度的控制了bean的生命周期:
public interface AutowireCapableBeanFactory extends BeanFactory {// 自动装配的常量,用于指示不同的自动装配模式int AUTOWIRE_NO = 0; // 不自动装配int AUTOWIRE_BY_NAME = 1; // 根据名称自动装配int AUTOWIRE_BY_TYPE = 2; // 根据类型自动装配int AUTOWIRE_CONSTRUCTOR = 3; // 使用构造器进行自动装配@Deprecatedint AUTOWIRE_AUTODETECT = 4; // 自动检测自动装配模式(已废弃)String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL"; // 用于标识原始实例的后缀// 创建给定类的新Bean实例,并应用所有的后处理器<T> T createBean(Class<T> var1) throws BeansException;// 自动装配现有的Bean实例,将Spring管理的Bean属性注入该实例void autowireBean(Object var1) throws BeansException;// 配置现有的Bean实例,将其与容器中的其他组件连接起来Object configureBean(Object var1, String var2) throws BeansException;// 按照指定的自动装配类型创建Bean实例Object createBean(Class<?> var1, int var2, boolean var3) throws BeansException;// 根据给定的类型和自动装配模式装配一个新的实例Object autowire(Class<?> var1, int var2, boolean var3) throws BeansException;// 自动装配Bean的属性void autowireBeanProperties(Object var1, int var2, boolean var3) throws BeansException;// 将Bean定义中的属性值应用到现有的Bean实例上void applyBeanPropertyValues(Object var1, String var2) throws BeansException;// 初始化Bean实例Object initializeBean(Object var1, String var2) throws BeansException;// 应用Bean的初始化前置处理器Object applyBeanPostProcessorsBeforeInitialization(Object var1, String var2) throws BeansException;// 应用Bean的初始化后置处理器Object applyBeanPostProcessorsAfterInitialization(Object var1, String var2) throws BeansException;// 销毁指定的Bean实例void destroyBean(Object var1);// 解析指定类型的Bean,并返回一个包含名称的Bean实例持有者<T> NamedBeanHolder<T> resolveNamedBean(Class<T> var1) throws BeansException;// 根据名称解析依赖关系Object resolveBeanByName(String var1, DependencyDescriptor var2) throws BeansException;// 解析给定的依赖关系@NullableObject resolveDependency(DependencyDescriptor var1, @Nullable String var2) throws BeansException;// 解析依赖关系,同时允许指定依赖名称集合和类型转换器@NullableObject resolveDependency(DependencyDescriptor var1, @Nullable String var2, @Nullable Set<String> var3, @Nullable TypeConverter var4) throws BeansException;
}
5、更强的配置能力
这个bean工厂接口并不用于正常的应用程序代码中。这个扩展接口只是为了允许框架内部的即插即用和对beanI厂配置方法的特殊访问,具体如下:
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {// 范围常量,定义了常见的 bean 生命周期String SCOPE_SINGLETON = "singleton";String SCOPE_PROTOTYPE = "prototype";// 设置父 BeanFactoryvoid setParentBeanFactory(BeanFactory var1) throws IllegalStateException;// 配置加载 bean 的类加载器void setBeanClassLoader(@Nullable ClassLoader var1);@Nullable ClassLoader getBeanClassLoader();void setTempClassLoader(@Nullable ClassLoader var1);@Nullable ClassLoader getTempClassLoader();// 配置 bean 元数据的缓存void setCacheBeanMetadata(boolean var1);boolean isCacheBeanMetadata();// 设置和获取自定义的 BeanExpressionResolver,处理 bean 定义中的表达式void setBeanExpressionResolver(@Nullable BeanExpressionResolver var1);@Nullable BeanExpressionResolver getBeanExpressionResolver();// 设置和获取自定义的 ConversionService,处理类型转换void setConversionService(@Nullable ConversionService var1);@Nullable ConversionService getConversionService();// 注册自定义的属性编辑器,并将其复制到 PropertyEditorRegistry 中void addPropertyEditorRegistrar(PropertyEditorRegistrar var1);void registerCustomEditor(Class<?> var1, Class<? extends PropertyEditor> var2);void copyRegisteredEditorsTo(PropertyEditorRegistry var1);// 配置和获取 TypeConverter,用于处理 bean 属性转换void setTypeConverter(TypeConverter var1);TypeConverter getTypeConverter();// 注册和解析 bean 定义中的嵌入式值void addEmbeddedValueResolver(StringValueResolver var1);boolean hasEmbeddedValueResolver();@Nullable String resolveEmbeddedValue(String var1);// 添加和管理 BeanPostProcessor,在初始化前后应用void addBeanPostProcessor(BeanPostProcessor var1);int getBeanPostProcessorCount();// 注册和获取自定义的作用域void registerScope(String var1, Scope var2);String[] getRegisteredScopeNames();@Nullable Scope getRegisteredScope(String var1);// 设置和获取 ApplicationStartup,用于跟踪应用程序启动过程void setApplicationStartup(ApplicationStartup var1);ApplicationStartup getApplicationStartup();// 获取 AccessControlContext,用于保障 bean 创建和访问的安全性AccessControlContext getAccessControlContext();// 复制来自其他 ConfigurableBeanFactory 的配置void copyConfigurationFrom(ConfigurableBeanFactory var1);// 管理 bean 的别名void registerAlias(String var1, String var2) throws BeanDefinitionStoreException;void resolveAliases(StringValueResolver var1);// 获取合并后的 bean 定义,处理覆盖和继承问题BeanDefinition getMergedBeanDefinition(String var1) throws NoSuchBeanDefinitionException;// 判断一个 bean 是否是 FactoryBean 类型boolean isFactoryBean(String var1) throws NoSuchBeanDefinitionException;// 设置和检查 bean 是否正在创建中void setCurrentlyInCreation(String var1, boolean var2);boolean isCurrentlyInCreation(String var1);// 管理 bean 之间的依赖关系void registerDependentBean(String var1, String var2);String[] getDependentBeans(String var1);String[] getDependenciesForBean(String var1);// 销毁指定的 bean 实例和处理作用域中的 beanvoid destroyBean(String var1, Object var2);void destroyScopedBean(String var1);// 销毁所有单例 beanvoid destroySingletons();
}
6、工厂的生命周期
bean工厂的生命周期比较简单: start->onRefresh-> Running->onClose->stop
每一个生命周期节点都会完成大量的工作,我们后边的内容会详细介绍:
public interface Lifecycle {void start(); // 启动方法,启动组件或服务void stop(); // 停止方法,停止组件或服务boolean isRunning(); // 判断当前组件或服务是否处于运行状态
}
public interface LifecycleProcessor extends Lifecycle {/*** 上下文刷新通知,例如自动启动组件。* 当上下文刷新时,会触发此方法,通常用于自动启动与上下文相关的组件或服务。*/void onRefresh(); /*** 上下文关闭阶段的通知,例如自动停止组件。* 当上下文关闭时,会触发此方法,通常用于自动停止与上下文相关的组件或服务。*/void onClose();
}
二、bean工厂的创建
一个典型的功能强大的bean工厂实现,就是DefaultListableBeanFactory, 事实上我们的容器中维护的beanFactory都是这个类的实例;
我们看一下该类的类图:
这里简单的总结一下, 一个完整的bean工厂应该具备哪些能力?
- bean工厂的基础能力,枚举bean,分层,自动装配、独立配置等。
- 注册单例bean (包括Factorybean) 的能力。
- 注册别名的能力。
尝试使用一下bean工厂
// 创建一个 Bean 工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();// 注册 Bean 定义,beanName 为 "user"
factory.registerBeanDefinition("user", beanDefinition);// 创建一个实例化策略,使用 Cglib 实现子类化来创建实例
InstantiationStrategy strategy = new CglibSubclassingInstantiationStrategy();// 使用策略实例化 Bean
Object user = strategy.instantiate(beanDefinition, "user", factory);// 输出实例化后的 Bean 信息
logger.info("user --> {}", user);
查看实例化strategy.instantiate
源码:
这个 instantiate
方法用于通过无参构造函数实例化一个 Bean。如果没有需要覆盖的方法,它将使用默认构造函数来创建实例;否则,会调用带有方法注入的实例化方式。
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {// 如果没有方法覆盖,直接使用构造函数实例化if (!bd.hasMethodOverrides()) {Constructor constructorToUse;// 同步块,确保在多线程环境中安全地解析构造函数synchronized(bd.constructorArgumentLock) {// 获取已解析的构造函数或工厂方法constructorToUse = (Constructor) bd.resolvedConstructorOrFactoryMethod;// 如果构造函数还未解析,进行解析if (constructorToUse == null) {Class<?> clazz = bd.getBeanClass();// 如果指定的类是接口,则抛出异常,因为接口无法直接实例化if (clazz.isInterface()) {throw new BeanInstantiationException(clazz, "Specified class is an interface");}try {// 处理安全管理器,若存在,则在受保护的环境中访问构造函数if (System.getSecurityManager() != null) {clazz.getClass(); // 获取类的字节码对象constructorToUse = (Constructor) AccessController.doPrivileged(() -> {return clazz.getDeclaredConstructor();});} else {// 无安全管理器的情况下直接获取默认构造函数constructorToUse = clazz.getDeclaredConstructor();}// 将解析后的构造函数缓存到 Bean 定义中,以后可以直接使用bd.resolvedConstructorOrFactoryMethod = constructorToUse;} catch (Throwable ex) {// 如果没有找到默认构造函数,抛出实例化异常throw new BeanInstantiationException(clazz, "No default constructor found", ex);}}}// 使用 BeanUtils 实例化对象,传入解析的构造函数和空参数return BeanUtils.instantiateClass(constructorToUse, new Object[0]);} else {// 否则,使用带方法注入的实例化方式return this.instantiateWithMethodInjection(bd, beanName, owner);}
}
其中的方法覆盖是指:(了解即可)
- lookup-method注入:
lookup-method注入是spring动态改变bean里方法的实现。指定方法的返回值为某个已经存在的bean。replaced-method
注入:
replaced- method注入是spring动态改变bean方法的-种实现。他可以改变的方法执行逻辑,将方法进行替换,定义替换方法的类(需要继承接口org.springframework.beans.factory.support.MethodReplacer)接口。
FactoryBean
通常用来帮我们去创建一些复杂对象,屏蔽复杂对象的创建过程,如将复杂的创建逻辑隐藏在getObject()
方法中
- 能够将
getObject()
方法返回的bean(默认是单例的)注册到容器中 - 也会将自身注册到容器中,想获取FactoryBean需要在名字前面加
&
public interface FactoryBean<T> {// 用于标识 FactoryBean 中生成对象的类型属性名String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";/*** 获取由此 FactoryBean 管理的对象实例。* @return 由此 FactoryBean 创建的对象实例* @throws Exception 如果创建过程出错*/@NullableT getObject() throws Exception;/*** 获取 FactoryBean 管理的对象类型。* @return FactoryBean 创建的对象类型*/@NullableClass<?> getObjectType();/*** 判断此 FactoryBean 创建的对象是否为单例。* 默认返回 true,表示 FactoryBean 管理的对象为单例。* @return 如果此 FactoryBean 创建的对象为单例,则返回 true,否则返回 false*/default boolean isSingleton() {return true;}
}
尝试使用FactoryBean:
@Component("user")
public class UserFactoryBean implements FactoryBean<User> {/*** 创建并返回 User 实例。* 这里可以包含复杂的创建逻辑,帮助我们生成复杂的对象。* @return User对象实例* @throws Exception 如果对象创建过程中出现问题*/@Overridepublic User getObject() throws Exception {// 可能包含复杂的逻辑,生成一个 User 实例return new User("it", 30);}/*** 返回 FactoryBean 管理的对象类型。* 在此情况下,返回 User.class 类型。* @return User.class*/@Overridepublic Class<?> getObjectType() {return User.class;}
}
测试类
Object user = beanFactory . getBean( name: "user") ;
object userFactory = beanFactory . getBean( name: "&user");
Logger. info("user -->{} ” ,user);
Logger. info("userFactory -->{} " , userFactory);
三、了解扩展点
spring给我们提供了很多的扩展点,这些扩展点可以允许我们在spring上下文启动的任意环节进行干预,实现自己的逻辑。大致将spring的启动环节画一个图,当然他可能不准确,我们只是想将大致的环节勾勒出来,然后看看其中的可以打展的地方。
其中比较重要的是beanFactory
的后置处理操作和bean
的后置处理操作
后置处理器:
在某些节点提供一些钩子函数,用于扩展,可以干预整个spring工厂的启动
这些方法会在特定的时间由框架进行主动调用,并把beanFactory返回
实现BeanFactoryPostProcessor
接口,实现BeanFactory后置处理器:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 在Spring容器初始化时,调用此方法对BeanFactory进行自定义处理System.out.println("beanFactory ------------->" + beanFactory);}
}
实现BeanPostProcessor
接口,实现堆Bean
创建后置处理器:
@Component
// 自定义 BeanPostProcessor 实现类
public class MyBeanPostProcessor implements BeanPostProcessor {// 在 Bean 初始化前执行的方法@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println(beanName + " --------------> postProcessBeforeInitialization");return bean; // 返回 Bean 本身,以便 Spring 继续初始化流程}// 在 Bean 初始化后执行的方法@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println(beanName + " --------------> postProcessAfterInitialization");return bean; // 返回 Bean 本身或包装后的 Bean}
}
四、认识ApplicationContext
ApplicationContext是应用程序的中央接口,提供一些便利的功能, 引导Spring的程序进行启动,他是我们学习spring中的重中之重,理解了ApplicationContext我们就学会了spring。
spring上下文提供了丰富的功能,拥有强大的能力,于切的spring的知识内其实都是为了服务一个ApplicationContext, 下图展示了Springpplication中的一些核心接口和类:
一个ApplicationContext继承了五个接口,共同为一个上下文赋能,这些接口我们都已经接触过了:
EnvironmentCapable
:提供一个上下文环境的能力ListableBeanFactory
:枚举bean工厂的bean的能力HierarchicalBeanFactory
:分层的能力MessageSource
:国际化的能力ApplicationEventPublisher
:发布事件的能力
// ApplicationContext接口是Spring框架的核心接口之一,它代表应用的上下文容器,负责管理Bean及其生命周期。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {// 获取ApplicationContext的唯一ID。@NullableString getId();// 获取应用的名称。String getApplicationName();// 获取ApplicationContext的显示名称,通常用于调试和日志。String getDisplayName();// 获取应用启动时间(时间戳),表示容器启动的时间。long getStartupDate();// 获取当前应用上下文的父上下文,如果没有则返回null。@NullableApplicationContext getParent();// 获取AutowireCapableBeanFactory,用于执行自动装配和实例化Bean的相关操作。AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
其子接口ConfigurableApplicationContext
对ApplicationContext
进行了扩展:
// ConfigurableApplicationContext接口扩展了ApplicationContext接口,提供了额外的配置方法,
// 允许在运行时对ApplicationContext进行动态调整和管理。
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {// 配置文件路径的分隔符常量,支持逗号、分号、空格和换行符。String CONFIG_LOCATION_DELIMITERS = ",; \t\n";// 重要的Bean名称常量,包括转换服务、加载时间编织器、环境配置等。String CONVERSION_SERVICE_BEAN_NAME = "conversionService";String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";String ENVIRONMENT_BEAN_NAME = "environment";String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";String APPLICATION_STARTUP_BEAN_NAME = "applicationStartup";String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";// 设置ApplicationContext的唯一ID。void setId(String var1);// 设置当前上下文的父上下文。void setParent(@Nullable ApplicationContext var1);// 设置用于环境配置的ConfigurableEnvironment对象。void setEnvironment(ConfigurableEnvironment var1);// 获取ConfigurableEnvironment实例,用于访问和配置环境属性。ConfigurableEnvironment getEnvironment();// 设置应用启动对象,用于记录启动阶段的性能信息。void setApplicationStartup(ApplicationStartup var1);// 获取应用启动对象。ApplicationStartup getApplicationStartup();// 向上下文中添加BeanFactory后置处理器。void addBeanFactoryPostProcessor(BeanFactoryPostProcessor var1);// 向上下文添加应用监听器,用于处理事件。void addApplicationListener(ApplicationListener<?> var1);// 设置类加载器。void setClassLoader(ClassLoader var1);// 添加协议解析器,用于自定义资源解析。void addProtocolResolver(ProtocolResolver var1);// 初始化或刷新上下文,加载或重建所有Bean的定义和实例。void refresh() throws BeansException, IllegalStateException;// 注册关闭钩子,以确保在JVM关闭时执行上下文的关闭操作。void registerShutdownHook();// 关闭ApplicationContext,释放资源。void close();// 检查上下文是否处于活跃状态。boolean isActive();// 获取可配置的BeanFactory,允许自定义Bean创建逻辑。ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
举几个例子,理解里面的函数:
- 实现了一个自定义容器类
MyGenericApplicationContext
,继承自GenericApplicationContext
,并重写了registerShutdownHook()
方法。
这个方法中注册了一个线程,当 JVM 关闭时,这个线程会被自动调用来执行资源清理或其他关闭操作。
// 自定义应用上下文类,继承自 GenericApplicationContext
public class MyGenericApplicationContext extends GenericApplicationContext {// 关闭钩子线程对象,用于在容器关闭时执行清理操作private Thread shutdownHook = null;@Overridepublic void registerShutdownHook() {// 检查是否已有关闭钩子线程被注册if (this.shutdownHook == null) {// 创建一个新的关闭钩子线程并命名this.shutdownHook = new Thread("SHUTDOWN_HOOK_THREAD_NAME") {@Overridepublic void run() {// 关闭钩子线程的运行逻辑System.out.println("容器关闭了,该干啥干啥吧!");}};// 将该线程注册为 JVM 的关闭钩子线程Runtime.getRuntime().addShutdownHook(this.shutdownHook);}}
}
- 加载配置文件并获取bean
// 创建 GenericApplicationContext 实例,并设置资源位置
GenericApplicationContext myGenericApplicationContext = new GenericXmlApplicationContext("classpath:config-file.xml");// 获取 TeddyDog 类型的 Bean 实例
TeddyDog bean = myGenericApplicationContext.getBean(TeddyDog.class);// 记录获取到的 Bean 信息
logger.info("dog ----> {}", bean);
接下来我们查看上下文容器的构建过程,先查看new GenericXmlApplicationContext();
源码:
public GenericXmlApplicationContext(String... resourceLocations) {// 加载指定路径的资源文件,并解析其中定义的 Beanthis.load(resourceLocations); // 刷新上下文,以便完成 Bean 的初始化工作this.refresh();
}
load()
其实就是调用loadBeanDefinitions()
,这个之前有说过。
当调用GenericXmlApplicationContext
构造时,会调用父类GenericApplicationContext
的无参构造:
public GenericApplicationContext() {// 标志是否使用自定义的类加载器,初始化为 false,表示默认不使用this.customClassLoader = false;// 使用原子布尔类型来标识上下文是否已刷新,初始状态为未刷新this.refreshed = new AtomicBoolean();// 创建一个默认的 Bean 工厂实例,用于管理和配置 Bean 的生命周期this.beanFactory = new DefaultListableBeanFactory();
}
可以看到在定义上下文的时候就会帮我们创建了一个BeanFactory
。
Bean
工厂本身就是一个注册器,因此load()
后会将BeandeFinition
扫描并注册到bean
工厂中。
紧接着下一个步骤就是:refresh()
刷新容器
第四章 刷新容器
我们看到的任何构建applicationContext
的过程都是两步走:
- 收集元数据
- 刷新容器.
刷新容器的核心目的就是实例化我们的容器和容器内的bean,这是spring最核心的地方,没有之一。
容器几乎所有的工作都会在这个时间段完成,但是有一个前提就是就是此时所有的元数据搜集工作应该完成,相应的beanDefinition
已经准备好了, 保存在DefaultlistableBeanFactory
的map
中:
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
查看AbstractApplicationContext
的refresh()
方法源码:
public void refresh() throws BeansException, IllegalStateException {// 加锁,防止在多线程环境中重复刷新synchronized (this.startupShutdownMonitor) {// 启动一个监测步骤,用于记录上下文刷新过程(不重要)StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 准备刷新过程(如初始化环境变量、检查环境配置等)this.prepareRefresh();// 获取一个新的 BeanFactory 实例,进行配置和管理 BeanConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();// 配置 BeanFactory,设置一些标准的容器属性和预配置this.prepareBeanFactory(beanFactory);try {// 提供对 BeanFactory 的后置处理(扩展点)this.postProcessBeanFactory(beanFactory);// 启动记录 Bean 后置处理步骤StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// 调用 BeanFactory 的后处理器(如修改 Bean 定义,添加其他 Bean)this.invokeBeanFactoryPostProcessors(beanFactory);// 注册 BeanPostProcessor,用于对 Bean 实例进行额外操作this.registerBeanPostProcessors(beanFactory);// 结束 Bean 后置处理的监测步骤beanPostProcess.end();// 初始化消息源(用于国际化消息处理)this.initMessageSource();// 初始化事件广播器(用于在容器中分发事件)this.initApplicationEventMulticaster();// 具体的刷新操作(如在子类中添加额外的初始化)this.onRefresh();// 注册监听器,确保能够响应容器事件this.registerListeners();// 完成 Bean 的初始化(最关键的,完成所有非懒加载的单例bean)this.finishBeanFactoryInitialization(beanFactory);// 完成刷新操作this.finishRefresh();} catch (BeansException ex) {// 捕获异常,记录警告信息并取消刷新if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);}// 销毁已创建的 Bean,释放资源this.destroyBeans();// 取消刷新操作,清除相关状态this.cancelRefresh(ex);// 抛出异常,以便调用方处理throw ex;} finally {// 重置缓存,清理一些通用资源this.resetCommonCaches();// 结束刷新监测步骤contextRefresh.end();}}
}
this.finishBeanFactoryInitialization(beanFactory);
完成 Bean 的初始化(最关键的,完成所有非懒加载的单例bean)
- 对于单例bean,其生命周期由spring容器来管理
- 非单例bean,spring只管生,不管死。其资源的回收由JVM来管理
大概步骤:
1.准备刷新➡2.获得一个新鲜的bean工厂➡3.为bean工厂做一些前期的准备➡4.留给子类做后置处理的函数➡5.调用bean工厂的后置处理器➡6.注册bean的后置处理器➡7.初始化消息源➡8.初始化多播器➡9.onRefresh()
留给子类作为刷新时的扩展点➡10.注册listener➡11.注册非懒加载的单例bean➡12.完成刷新
若失败:
1.销毁所有的bean➡2.取消刷新
无论失败与否:
1.清除缓存➡2.标记刷新结束
1、准备刷新:prepareRefresh源码
此方法在 Spring 容器刷新之前进行一些初始化和验证操作,为容器的启动做准备。
protected void prepareRefresh() {// 设置启动时间为当前时间,用于后续的统计和监控this.startupDate = System.currentTimeMillis();// 更新容器状态,标记为已开启且未关闭this.closed.set(false);this.active.set(true);// 记录调试日志,输出刷新操作开始的信息if (this.logger.isDebugEnabled()) {if (this.logger.isTraceEnabled()) {this.logger.trace("Refreshing " + this);} else {this.logger.debug("Refreshing " + this.getDisplayName());}}// 初始化属性源,用于子类扩展方法配置属性源(例如加载环境变量等)this.initPropertySources();// 校验环境变量,确保所有必需的属性已设置this.getEnvironment().validateRequiredProperties();// 初始化早期事件监听器集合if (this.earlyApplicationListeners == null) {// 若首次刷新,记录当前的事件监听器this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);} else {// 若不是首次刷新,清空并重置为初始监听器集合this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);}// 初始化早期应用事件集合,用于存储在刷新期间的事件,便于后续统一处理this.earlyApplicationEvents = new LinkedHashSet<>();
}
该函数主要做的事情:
initPropertySources
用于加载并初始化属性源validateRequiredProperties
校验属性是否为空- 初始化早期事件监听器集合
initPropertySources
用于加载并初始化属性源(键值对),说明环境已经准备好了。
那么环境是什么时候准备好的,该抽象类中提供了两个方法:
如果环境不存在则新new
一个StandardEnvironment
/*** 获取当前的环境对象,如果环境对象为空,则创建并初始化一个新的标准环境。* @return 当前应用上下文的环境对象*/
public ConfigurableEnvironment getEnvironment() {// 检查环境对象是否为 null,如果是则调用 createEnvironment() 方法创建新实例if (this.environment == null) {this.environment = this.createEnvironment();}// 返回环境对象return this.environment;
}/*** 创建一个新的 ConfigurableEnvironment 实例。* 可在子类中重写以提供自定义的环境配置。* @return 新的标准环境对象*/
protected ConfigurableEnvironment createEnvironment() {// 返回标准的 ConfigurableEnvironment 实现return new StandardEnvironment();
}
继续查看initPropertySources()
具体实现的源码:
/*** 初始化属性源,将环境对象中的属性源进行配置。* 如果当前环境是 Web 环境(ConfigurableWebEnvironment),则进行 Web 环境的初始化。*/
protected void initPropertySources() {// 获取当前环境对象ConfigurableEnvironment env = this.getEnvironment();// 如果当前环境是 Web 环境,则进行 Web 环境的属性源初始化if (env instanceof ConfigurableWebEnvironment) {// 将 servletContext 传递给 ConfigurableWebEnvironment 的 initPropertySources 方法((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, (ServletConfig) null);}
}
进一步查看initPropertySources
源码,
/*** 初始化 Web 环境下的属性源。* 通过调用 WebApplicationContextUtils 的 initServletPropertySources 方法,初始化与 servletContext 和 servletConfig 相关的属性源。** @param servletContext 当前应用的 ServletContext,提供 Web 应用的上下文信息。* @param servletConfig 当前应用的 ServletConfig,提供 Servlet 配置信息。*/
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {// 调用 WebApplicationContextUtils 的 initServletPropertySources 方法初始化属性源WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);
}
进一步看initServletPropertySources
源码:
/*** 初始化 Servlet 环境中的属性源,将 ServletContext 和 ServletConfig 中的初始化参数添加到 Spring 环境的属性源中。** @param sources Spring 环境中的属性源集合。* @param servletContext 当前应用的 ServletContext,提供 Web 应用的上下文信息。* @param servletConfig 当前应用的 ServletConfig,提供 Web 应用的初始化配置信息。*/
public static void initServletPropertySources(MutablePropertySources sources, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {// 确保 sources 不为 nullAssert.notNull(sources, "'propertySources' must not be null");// 处理 ServletContext 中的初始化参数String name = "servletContextInitParams";if (servletContext != null && sources.get(name) instanceof StubPropertySource) {// 如果 ServletContext 不为 null 且对应的属性源是 StubPropertySource,则替换成新的 ServletContextPropertySourcesources.replace(name, new ServletContextPropertySource(name, servletContext));}// 处理 ServletConfig 中的初始化参数name = "servletConfigInitParams";if (servletConfig != null && sources.get(name) instanceof StubPropertySource) {// 如果 ServletConfig 不为 null 且对应的属性源是 StubPropertySource,则替换成新的 ServletConfigPropertySourcesources.replace(name, new ServletConfigPropertySource(name, servletConfig));}
}
上面的代码主要做的是将name="servletContextInitParams"
和name = "servletConfigInitParams"
进行替换,并设置到spring
中去
因此initPropertySources()
是一个扩展点,Web容器的上下文会在该方法中进行一些初始化的操作,将serverlet容器里的两个配置添加到环境中,将spring上下文和servlet上下文做勾连。
2、获得一个新鲜的bean工厂:obtainFreshBeanFactory源码
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
进一步查看:
/*** 获取一个新的、已刷新的 BeanFactory 实例。* * @return 刷新后的 ConfigurableListableBeanFactory 实例。*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 刷新 BeanFactorythis.refreshBeanFactory();// 返回当前的 BeanFactory 实例return this.getBeanFactory();
}
查看具体实现类GenericApplicationContext
是怎么获取beanFactory
的:
public final ConfigurableListableBeanFactory getBeanFactory() { return this.beanFactory;
}
这个beanFactory
在空参构造的时候就会给我们构建好:
public GenericApplicationContext() { this.customClassLoader = false; this.refreshed = new AtomicBoolean(); this.beanFactory = new DefaultListableBeanFactory();
}
查看GenericApplicationContext
的refreshBeanFactory
方法:
/*** 刷新 BeanFactory,确保只进行一次刷新操作。* * @throws IllegalStateException 如果尝试进行多次刷新,则抛出异常。*/
protected final void refreshBeanFactory() throws IllegalStateException {// 使用 AtomicBoolean 来确保只执行一次刷新操作if (!this.refreshed.compareAndSet(false, true)) {// 如果 refreshed 为 true,表示已经进行了刷新,抛出异常throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");} else {// 设置 BeanFactory 的序列化 IDthis.beanFactory.setSerializationId(this.getId());}
}
由上述代码可知道,BeanFactory
只支持一次刷新。
AbstractRefreshableApplicationContext
该实现类的beanFactory
是支持多次刷新的
3、为bean工厂做一些前期的准备:prepareBeanFactory(beanFactory)
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 设置 BeanClassLoader,指定类加载器,用于加载 Bean 类beanFactory.setBeanClassLoader(this.getClassLoader());// 如果不应该忽略 SpEL(Spring 表达式语言),则设置表达式解析器if (!shouldIgnoreSpel) {beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));}// 添加自定义的属性编辑器注册器,用于处理特定类型的属性转换beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));// 向 BeanFactory 中添加一个 Bean 后处理器,处理应用上下文相关的处理beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 忽略一些与环境相关的接口,这意味着这些接口将不会被自动注入beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);// 注册一些可解析的依赖关系,允许在 Bean 中注入这些接口的实例beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// 添加一个新的 Bean 后处理器,用于检测应用事件监听器beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// 如果不是在原生镜像中,并且 BeanFactory 中包含名为 "loadTimeWeaver" 的 Bean,则添加一个新的后处理器if (!NativeDetector.inNativeImage() && beanFactory.containsBean("loadTimeWeaver")) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}// 如果 BeanFactory 中没有名为 "environment" 的 Bean,则注册一个单例 Beanif (!beanFactory.containsLocalBean("environment")) {beanFactory.registerSingleton("environment", this.getEnvironment());}// 如果 BeanFactory 中没有名为 "systemProperties" 的 Bean,则注册一个单例 Beanif (!beanFactory.containsLocalBean("systemProperties")) {beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());}// 如果 BeanFactory 中没有名为 "systemEnvironment" 的 Bean,则注册一个单例 Beanif (!beanFactory.containsLocalBean("systemEnvironment")) {beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());}// 如果 BeanFactory 中没有名为 "applicationStartup" 的 Bean,则注册一个单例 Beanif (!beanFactory.containsLocalBean("applicationStartup")) {beanFactory.registerSingleton("applicationStartup", this.getApplicationStartup());}
}
- 这段代码的作用是配置
beanFactory
忽略对特定接口的依赖注入。也就是说,当某个 bean 实现了这些接口时,Spring 容器不会自动将对应的资源注入到这些 bean 中,而是会忽略它们的依赖注入。这在某些情况下可以防止不必要的依赖注入,从而提升性能或避免复杂的依赖链。
beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
忽略了以上的资源,但是需要在特定时间去调用并设置这些资源类。ApplicationContextAwareProcessor
中提供了一个函数:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 检查 bean 是否实现了指定的 Aware 接口// 如果没有实现这些接口,直接返回 bean,不做进一步处理if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware) && !(bean instanceof ApplicationStartupAware)) {return bean;} else {// 初始化访问控制上下文,用于在安全受限环境中进行权限控制AccessControlContext acc = null;if (System.getSecurityManager() != null) {acc = this.applicationContext.getBeanFactory().getAccessControlContext();}// 如果存在安全上下文,在其权限控制下调用 invokeAwareInterfaces 方法if (acc != null) {AccessController.doPrivileged(() -> {this.invokeAwareInterfaces(bean);return null;}, acc);} else {// 否则直接调用 invokeAwareInterfaces 方法this.invokeAwareInterfaces(bean);}// 返回处理后的 beanreturn bean;}
}
进一步看invokeAwareInterfaces
:
private void invokeAwareInterfaces(Object bean) {// 如果 bean 实现了 EnvironmentAware 接口,注入 Environment 实例if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}// 如果 bean 实现了 EmbeddedValueResolverAware 接口,注入 EmbeddedValueResolver 实例if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);}// 如果 bean 实现了 ResourceLoaderAware 接口,注入 ResourceLoader 实例(这里是 applicationContext)if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}// 如果 bean 实现了 ApplicationEventPublisherAware 接口,注入 ApplicationEventPublisher 实例if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}// 如果 bean 实现了 MessageSourceAware 接口,注入 MessageSource 实例if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}// 如果 bean 实现了 ApplicationStartupAware 接口,注入 ApplicationStartup 实例if (bean instanceof ApplicationStartupAware) {((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());}// 如果 bean 实现了 ApplicationContextAware 接口,注入 ApplicationContext 实例if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}
}
- 下面这段代码注册了可解析的依赖关系。
// 注册一些可解析的依赖关系,允许在 Bean 中注入这些接口的实例beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this)
如果某个 bean 的构造函数或字段需要注入 BeanFactory
、ResourceLoader
、ApplicationEventPublisher
或 ApplicationContext
,那么 Spring 容器就能自动提供这些依赖。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
:
该处是添加一个后置处理器ApplicationListenerDetector
,该类是一个监听器,能够帮我们探测哪些bean
是listener
,并帮我们注册到多播器中
public Object postProcessAfterInitialization(Object bean, String beanName) {// 检查当前 Bean 是否实现了 ApplicationListener 接口if (bean instanceof ApplicationListener) {// 从 singletonNames 中获取 beanName 对应的 Boolean 值,// 表示该 Bean 是否是单例 (singleton)。Boolean flag = (Boolean) this.singletonNames.get(beanName);// 如果该 Bean 是单例 (flag 为 true),则将其注册为事件监听器if (Boolean.TRUE.equals(flag)) {this.applicationContext.addApplicationListener((ApplicationListener)bean);} // 如果不是单例 (flag 为 false)else if (Boolean.FALSE.equals(flag)) {// 如果是非单例并且没有在容器中注册该 Bean 时,输出警告日志if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface but is not reachable for event multicasting by its containing ApplicationContext because it does not have singleton scope. Only top-level listener beans are allowed to be of non-singleton scope.");}// 移除非单例监听器 Bean 的名称,防止后续重复注册this.singletonNames.remove(beanName);}}// 返回处理后的 Bean(未做修改的 Bean)return bean;
}
4、留给子类做后置处理的函数
// 提供对 BeanFactory 的后置处理(扩展点)
this.postProcessBeanFactory(beanFactory);// 调用 BeanFactory 的后处理器(如修改 Bean 定义,添加其他 Bean)
this.invokeBeanFactoryPostProcessors(beanFactory);
这两个函数在功能上类似,但是还是存在一些区别:
-
postProcessBeanFactory(beanFactory)
- 目的:提供一个对
BeanFactory
进行自定义修改的扩展点。 - 调用者:通常是框架的具体实现类,例如
AbstractApplicationContext
。
- 目的:提供一个对
-
invokeBeanFactoryPostProcessors(beanFactory)
- 目的:调用所有注册的
BeanFactoryPostProcessor
实现类。 - 调用者:由 Spring 框架自动调用。
- 目的:调用所有注册的
即
postProcessBeanFactory(beanFactory)
一般是框架的开发者写的,invokeBeanFactoryPostProcessors(beanFactory)
一般是spring使用的开发人员写的。
查看postProcessBeanFactory(beanFactory)
的一个具体实现:
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {//检查当前 `ApplicationContext` 是否有一个有效的 `ServletContext`(即当前环境是否为 Web 环境)。如果不在 Web 环境下,`servletContext` 可能为空。if (this.servletContext != null) {//添加了一个 `ServletContextAwareProcessor` 后置处理器。`ServletContextAwareProcessor` 是一个 `BeanPostProcessor`,专门用于处理实现了 `ServletContextAware` 接口的 Bean。它会将 `ServletContext` 注入到实现了 `ServletContextAware` 接口的 Bean 中,使这些 Bean 能够访问到 Web 应用的 `ServletContext`。beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));//告知 `BeanFactory`,对于实现了 `ServletContextAware` 接口的 Bean,自动装配时忽略 `ServletContextAware` 接口。因为依赖注入已经由 `ServletContextAwareProcessor` 负责处理,所以在这里忽略它可以避免重复注入。beanFactory.ignoreDependencyInterface(ServletContextAware.class);}// 注册 Web 应用特有的作用域,比如 request 和 session 作用域WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);// 将 Web 环境中的特殊 Bean(如 ServletContext)注册到 beanFactory 中 // 使得其他组件可以通过依赖注入直接访问这些 BeanWebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
}
5、调用bean工厂的后置处理器
查看invokeBeanFactoryPostProcessors
源码:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors()); if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
主要看第一行代码PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// 用于记录已经处理过的 Bean 名称,避免重复处理Set<String> processedBeans = new HashSet();ArrayList<BeanFactoryPostProcessor> regularPostProcessors;ArrayList<BeanDefinitionRegistryPostProcessor> registryProcessors;// 如果 beanFactory 是 BeanDefinitionRegistry 的实例(常见于可注册 Bean 的环境)if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;regularPostProcessors = new ArrayList<>();registryProcessors = new ArrayList<>();// 分类传入的 PostProcessor 列表for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {// 如果是 BeanDefinitionRegistryPostProcessor,调用其注册处理方法((BeanDefinitionRegistryPostProcessor) postProcessor).postProcessBeanDefinitionRegistry(registry);registryProcessors.add((BeanDefinitionRegistryPostProcessor) postProcessor);} else {// 如果是普通的 BeanFactoryPostProcessorregularPostProcessors.add(postProcessor);}}// 处理 BeanDefinitionRegistryPostProcessorArrayList<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// 获取所有注册的 BeanDefinitionRegistryPostProcessor 类型的 BeanString[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);// 按 PriorityOrdered 排序并调用for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());currentRegistryProcessors.clear();// 按 Ordered 排序并调用postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());currentRegistryProcessors.clear();// 最后调用所有剩余未排序的 BeanDefinitionRegistryPostProcessorboolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());currentRegistryProcessors.clear();}// 调用所有处理后的 BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);} else {// 如果不是 BeanDefinitionRegistry,只处理普通的 BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// 获取 BeanFactoryPostProcessor 类型的 Bean 名称String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);regularPostProcessors = new ArrayList<>();registryProcessors = new ArrayList<>();currentRegistryProcessors = new ArrayList<>();// 分类剩余的 BeanFactoryPostProcessor 并根据优先级处理for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {regularPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {registryProcessors.add(ppName);} else {currentRegistryProcessors.add(ppName);}}}// 按优先级排序并调用所有剩余的 PostProcessorsortPostProcessors(regularPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);// 处理 Ordered 类型的 BeanFactoryPostProcessorList<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(registryProcessors.size());for (String postProcessorName : registryProcessors) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// 调用无序的 BeanFactoryPostProcessorList<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(currentRegistryProcessors.size());for (String ppName : currentRegistryProcessors) {nonOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// 清除元数据缓存以确保 Bean 定义的完整性beanFactory.clearMetadataCache();
}
什么是BeanDefinitionRegistryPostProcessor
?
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
}
BeanDefinitionRegistryPostProcessor
是 Spring 框架中的一个接口,它扩展了 BeanFactoryPostProcessor
接口。与 BeanFactoryPostProcessor
不同的是,BeanDefinitionRegistryPostProcessor
可以在 Spring 容器加载 Bean
之前,进一步自定义和修改 Bean
的定义信息。其主要特点是能够访问 BeanDefinitionRegistry
,因此可以动态注册、修改或移除 BeanDefinition
(即 Bean
的定义信息)。
BeanDefinitionRegistryPostProcessor
主要包括以下两个方法:
- postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry):
用于在所有Bean
定义被加载但尚未初始化时修改或注册BeanDefinition
。通过传入的BeanDefinitionRegistry
对象,可以动态地注册、修改或删除BeanDefinition
。 - postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory):
继承自BeanFactoryPostProcessor
,用于在BeanFactory
实例化所有单例Bean
前,修改BeanFactory
的设置。这个方法更倾向于整体BeanFactory
的配置,而非单个BeanDefinition
。
PostProcessor
可以PriorityOrdered
或Ordered
来实现优先级调用或者调用次序。
大致流程总结:
- 首先执行
BeanDefinitionRegistryPostProcessor
:
- 按照
PriorityOrdered
优先级排序并执行。- 按照
Ordered
优先级排序并执行。- 处理无序的
BeanDefinitionRegistryPostProcessor
。- 递归检查是否有新的处理器需要执行。
- 然后执行普通的
BeanFactoryPostProcessor
:
- 按照
PriorityOrdered
排序并执行。- 按照
Ordered
排序并执行。- 执行没有优先级的
BeanFactoryPostProcessor
。
- 最后清除元数据缓存,以确保
BeanDefinition
处理的完整性。
6、注册bean的后置处理器
registerBeanPostProcessors
源码:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
继续深入查看:
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {// 获取所有 BeanPostProcessor 类型的 Bean 名称String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);// 计算目标 BeanPostProcessor 数量int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;// 为 BeanFactory 添加一个检查器,用于确保 BeanPostProcessor 注册正确beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));// 创建不同类型的 BeanPostProcessor 列表List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); // 存储 PriorityOrdered 类型的 BeanPostProcessorList<BeanPostProcessor> internalPostProcessors = new ArrayList<>(); // 存储 MergedBeanDefinitionPostProcessor 类型的 BeanPostProcessorList<String> orderedPostProcessorNames = new ArrayList<>(); // 存储 Ordered 类型的 BeanPostProcessor 名称List<String> nonOrderedPostProcessorNames = new ArrayList<>(); // 存储没有排序的 BeanPostProcessor 名称// 遍历所有 BeanPostProcessor,进行分类for (int var10 = 0; var10 < postProcessorNames.length; ++var10) {String ppName = postProcessorNames[var10];// 如果是 PriorityOrdered 类型,加入 priorityOrderedPostProcessorsif (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {BeanPostProcessor pp = (BeanPostProcessor) beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);// 如果是 MergedBeanDefinitionPostProcessor 类型的 BeanPostProcessor,加入 internalPostProcessorsif (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}} // 如果是 Ordered 类型,加入 orderedPostProcessorNameselse if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);} // 如果没有实现排序接口,则加入 nonOrderedPostProcessorNameselse {nonOrderedPostProcessorNames.add(ppName);}}// 对 PriorityOrdered 类型的 BeanPostProcessor 进行排序并注册sortPostProcessors(priorityOrderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);// 对 Ordered 类型的 BeanPostProcessor 进行处理List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String ppName : orderedPostProcessorNames) {BeanPostProcessor pp = (BeanPostProcessor) beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);// 如果是 MergedBeanDefinitionPostProcessor 类型的,加入 internalPostProcessorsif (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}// 对 Ordered 类型的 BeanPostProcessor 进行排序并注册sortPostProcessors(orderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, orderedPostProcessors);// 对没有排序的 BeanPostProcessor 进行处理List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String ppName : nonOrderedPostProcessorNames) {BeanPostProcessor pp = (BeanPostProcessor) beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);// 如果是 MergedBeanDefinitionPostProcessor 类型的,加入 internalPostProcessorsif (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}// 注册没有排序的 BeanPostProcessorregisterBeanPostProcessors(beanFactory, nonOrderedPostProcessors);// 对 MergedBeanDefinitionPostProcessor 类型的 BeanPostProcessor 进行排序并注册sortPostProcessors(internalPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, internalPostProcessors);// 最后,注册 ApplicationListenerDetector,它用于检测并注册实现了 ApplicationListener 的 BeanbeanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
这里涉及到MergedBeanDefinitionPostProcessor
,这是BeanDefinitionPostProcessor
的一个子接口:
- Bean生命周期的第一步就是合并Bean的定义
MergedBeanDefinitionPostProcessor
是 Spring 框架中的一个接口,它继承自BeanPostProcessor
,主要用于在 Bean 定义合并之后、Bean 实例化之前对 Bean 定义进行修改。
有个小细节:
在第一次遍历时,PriorityOrdered
类型的BeanDefinitionPostProcessor
会实例化然后加到链表中;而其它类型的加到链表中的是它们的名字,待后续进行遍历实例化。
这是为了按顺序进行实例化
注册的过程比较简单,就是拿到Bean工厂然后注册进去:
private static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {// 判断 beanFactory 是否是 AbstractBeanFactory 的实例if (beanFactory instanceof AbstractBeanFactory) {// 如果是 AbstractBeanFactory,则直接使用 addBeanPostProcessors 批量注册 BeanPostProcessor((AbstractBeanFactory) beanFactory).addBeanPostProcessors(postProcessors);} else {// 如果不是 AbstractBeanFactory,逐个遍历 postProcessors 列表,逐个注册 BeanPostProcessorIterator var2 = postProcessors.iterator();while (var2.hasNext()) {// 获取当前的 BeanPostProcessorBeanPostProcessor postProcessor = (BeanPostProcessor) var2.next();// 注册到 beanFactory 中beanFactory.addBeanPostProcessor(postProcessor);}}
}
注:这里仅是注册,并未调用
7.初始化消息源➡8.初始化多播器➡9.onRefresh()
初始化消息initMessageSource
消息:
protected void initMessageSource() {// 获取当前 BeanFactory,用于从中获取/注册 BeanConfigurableListableBeanFactory beanFactory = this.getBeanFactory();// 检查 BeanFactory 中是否已经存在名为 "messageSource" 的 Beanif (beanFactory.containsLocalBean("messageSource")) {// 如果存在,获取该 "messageSource" Bean,并转换为 MessageSource 类型this.messageSource = (MessageSource) beanFactory.getBean("messageSource", MessageSource.class);// 如果当前 messageSource 是 HierarchicalMessageSource 类型,并且父级 MessageSource 为空if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {// 将 messageSource 的父 MessageSource 设置为内部父级 MessageSourceHierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;if (hms.getParentMessageSource() == null) {hms.setParentMessageSource(this.getInternalParentMessageSource());}}// 如果日志级别为 TRACE,输出调试日志,显示正在使用的 messageSourceif (this.logger.isTraceEnabled()) {this.logger.trace("Using MessageSource [" + this.messageSource + "]");}} else {// 如果 BeanFactory 中没有名为 "messageSource" 的 Bean,创建一个 DelegatingMessageSource 实例DelegatingMessageSource dms = new DelegatingMessageSource();// 设置 DelegatingMessageSource 的父级 MessageSourcedms.setParentMessageSource(this.getInternalParentMessageSource());this.messageSource = dms;// 将新的 messageSource 注册为 BeanFactory 中的单例 beanbeanFactory.registerSingleton("messageSource", this.messageSource);// 如果日志级别为 TRACE,输出调试日志,显示创建并使用的新 messageSourceif (this.logger.isTraceEnabled()) {this.logger.trace("No 'messageSource' bean, using [" + this.messageSource + "]");}}
}
初始化多播器:
protected void initApplicationEventMulticaster() {// 获取当前的 BeanFactory,用于从中获取或注册 BeanConfigurableListableBeanFactory beanFactory = this.getBeanFactory();// 检查 BeanFactory 中是否存在名为 "applicationEventMulticaster" 的 Beanif (beanFactory.containsLocalBean("applicationEventMulticaster")) {// 如果存在,获取该 Bean 并转换为 ApplicationEventMulticaster 类型this.applicationEventMulticaster = (ApplicationEventMulticaster) beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);// 如果日志级别为 TRACE,输出调试日志,显示正在使用的 applicationEventMulticasterif (this.logger.isTraceEnabled()) {this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}} else {// 如果 BeanFactory 中没有名为 "applicationEventMulticaster" 的 Bean,创建一个 SimpleApplicationEventMulticaster 实例this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);// 将新的 applicationEventMulticaster 注册为 BeanFactory 中的单例 BeanbeanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);// 如果日志级别为 TRACE,输出调试日志,说明没有找到 "applicationEventMulticaster" Bean,因此创建了一个新的实例if (this.logger.isTraceEnabled()) {this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");}}
}
OnFresh()
查看其一个具体子类的实现:
protected void onRefresh() { super.onRefresh(); try { this.createWebServer(); } catch (Throwable var2) { throw new ApplicationContextException("Unable to start web server", var2); }
}
其在对单例的bean实例化之前,创建了一个WebServer
:
private void createWebServer() {// 获取当前 Web 服务器实例WebServer webServer = this.webServer;// 获取当前的 ServletContextServletContext servletContext = this.getServletContext();// 如果 webServer 为 null 且 servletContext 也为 null(通常是第一次启动时)if (webServer == null && servletContext == null) {// 开始记录启动的步骤StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");// 获取 Web 服务器工厂,这个工厂负责创建 Web 服务器ServletWebServerFactory factory = this.getWebServerFactory();// 给启动步骤添加标签,记录工厂类型createWebServer.tag("factory", factory.getClass().toString());// 通过工厂创建 Web 服务器,并使用 `ServletContextInitializer` 来初始化服务器this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});// 结束记录启动步骤createWebServer.end();// 注册 `WebServerGracefulShutdownLifecycle` 生命周期处理器用于优雅关机this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));// 注册 `WebServerStartStopLifecycle` 生命周期处理器,用于启动和停止 Web 服务器this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));}// 如果已经有 ServletContext,调用初始化方法else if (servletContext != null) {try {// 调用自定义的 ServletContext 初始化方法this.getSelfInitializer().onStartup(servletContext);} catch (ServletException var5) {// 捕获 ServletException 异常并抛出为 ApplicationContextExceptionthrow new ApplicationContextException("Cannot initialize servlet context", var5);}}// 初始化属性源(如配置文件、环境变量等)this.initPropertySources();
}
在创建WebServer工厂时,可以获得不同的Server工厂:
因此,在Onfresh()中会帮我们启动Tomcat服务器
10、注册listener
protected void registerListeners() {// 获取应用的监听器列表并遍历Iterator var1 = this.getApplicationListeners().iterator();while (var1.hasNext()) {// 获取每个应用事件监听器ApplicationListener<?> listener = (ApplicationListener)var1.next();// 将监听器添加到应用事件多播器中this.getApplicationEventMulticaster().addApplicationListener(listener);}// 获取所有类型为 ApplicationListener 的 bean 名称String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);String[] var7 = listenerBeanNames;int var3 = listenerBeanNames.length;// 遍历这些 bean 名称并将对应的监听器添加到应用事件多播器中for (int var4 = 0; var4 < var3; ++var4) {String listenerBeanName = var7[var4];// 添加监听器 beanthis.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// 获取早期的应用事件(如果有的话)Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;// 将 earlyApplicationEvents 置为 null,防止重复处理this.earlyApplicationEvents = null;// 如果有早期的应用事件,则广播它们if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {Iterator var9 = earlyEventsToProcess.iterator();while (var9.hasNext()) {// 获取每个早期事件ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();// 将事件广播出去this.getApplicationEventMulticaster().multicastEvent(earlyEvent);}}
}
11、注册非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory)
注意做的是实例化单例bean
,是比较核心的方法
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 如果 BeanFactory 中存在名为 "conversionService" 的 Bean 且类型为 ConversionService,则将该 ConversionService 设置为当前 BeanFactory 的 ConversionServiceif (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));}// 如果 BeanFactory 尚未配置嵌入式值解析器(embedded value resolver),则添加一个解析器,用于解析嵌入的占位符(例如,${...})if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver((strVal) -> {return this.getEnvironment().resolvePlaceholders(strVal); // 使用环境中的配置解析占位符});}// 获取所有实现了 LoadTimeWeaverAware 接口的 Bean 名称(这些 Bean 会感知类加载器的变化)String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);String[] var3 = weaverAwareNames;int var4 = weaverAwareNames.length;// 遍历这些实现了 LoadTimeWeaverAware 接口的 Bean,触发它们的初始化for (int var5 = 0; var5 < var4; ++var5) {String weaverAwareName = var3[var5];this.getBean(weaverAwareName); // 获取并初始化这些 Bean}// 设置 BeanFactory 的临时类加载器为 null,通常在完成 BeanFactory 初始化后释放不再需要的类加载器beanFactory.setTempClassLoader((ClassLoader)null);// 冻结 BeanFactory 配置,意味着后续无法再修改其配置beanFactory.freezeConfiguration();// 预先实例化所有单例 Bean,确保所有 Bean 都已初始化beanFactory.preInstantiateSingletons();
}
在进行实例化之前,会冻结beanFactory
的所有配置:
public void freezeConfiguration() {// 将 configurationFrozen 设置为 true,表示 BeanFactory 的配置已经被冻结,不允许进一步修改this.configurationFrozen = true;// 将 beanDefinitionNames(Bean 定义名称的集合)转换为字符串数组,并保存到 frozenBeanDefinitionNames 中// 这使得 Bean 定义名称不可再修改,因为 frozenBeanDefinitionNames 是被冻结的副本this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}
然后进行实例化所有单例Bean
:
public void preInstantiateSingletons() throws BeansException {// 如果日志级别是 TRACE,则输出调试信息,表示正在进行单例 Bean 的预实例化if (this.logger.isTraceEnabled()) {this.logger.trace("Pre-instantiating singletons in " + this);}// 获取所有的 Bean 定义名称,并将其存储在一个新的列表中List<String> beanNames = new ArrayList(this.beanDefinitionNames);Iterator var2 = beanNames.iterator();// 第一个循环:实例化所有符合条件的单例 BeanString beanName;while(var2.hasNext()) {beanName = (String)var2.next();// 获取该 Bean 的合并后的 Bean 定义(包含父类的定义)RootBeanDefinition bd = this.getMergedLocalBeanDefinition(beanName);// 检查 Bean 是否是抽象的、是否是单例、是否需要懒加载if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {// 如果是工厂 Bean,先从工厂获取 Bean 实例if (this.isFactoryBean(beanName)) {Object bean = this.getBean("&" + beanName);// 如果是 SmartFactoryBean,并且标记为急切初始化,则提前初始化该 Beanif (bean instanceof SmartFactoryBean) {SmartFactoryBean<?> smartFactoryBean = (SmartFactoryBean)bean;if (smartFactoryBean.isEagerInit()) {this.getBean(beanName);}}} else {// 直接获取普通的单例 Beanthis.getBean(beanName);}}}// 第二个循环:处理所有实现了 SmartInitializingSingleton 的单例 Beanvar2 = beanNames.iterator();while(var2.hasNext()) {beanName = (String)var2.next();// 获取 Bean 的实例Object singletonInstance = this.getSingleton(beanName);// 如果该 Bean 实现了 SmartInitializingSingleton 接口,则调用 afterSingletonsInstantiated()if (singletonInstance instanceof SmartInitializingSingleton) {SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;// 记录启动步骤,表示智能初始化的过程StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize").tag("beanName", beanName);// 调用 afterSingletonsInstantiated() 方法smartSingleton.afterSingletonsInstantiated();// 结束启动步骤smartInitialize.end();}}
}
- 首先创建一个
beanDefinitionNames
的样本:
List<String> beanNames = new ArrayList(this.beanDefinitionNames);
- 这种对全局变量创建副本的方式能够避免线程安全的问题,因为方法里的局部变量不存在线程安全问题 - 在对
beanNames
进行遍历时- 合并
Bean
的定义 - 判断是否是非抽象的、单例且不是懒加载的
- 是否是工厂
- 是工厂,通过前缀
&
获取工厂实例- 判断是否需要紧急初始化
- 不是工厂则通过实例化获取
bean
- 是工厂,通过前缀
- 是否是工厂
- 合并
- 处理所有实现了
SmartInitializingSingleton
的单例 Bean- 会在所有单例
bean
实例化后,统一调用实现了SmartInitializingSingleton
接口的的bean
的afterSingletonsInstantiated()
方法
- 会在所有单例
SmartInitializingSingleton
是 Spring 框架中的一个接口,主要用于在 Spring 容器初始化过程中,在所有单例 Bean 实例化后执行额外的操作。它提供了一个回调方法afterSingletonsInstantiated()
,该方法会在所有单例 Bean 完成实例化后被调用。
这个算一个扩展点:在所有bean
都实例化后我们该干些什么
12、完成刷新
protected void finishRefresh() {// 清理资源缓存,释放不再需要的资源this.clearResourceCaches();// 初始化生命周期处理器,处理与生命周期相关的操作this.initLifecycleProcessor();// 通过生命周期处理器执行“刷新”操作,通常会调用某些 bean 的生命周期方法this.getLifecycleProcessor().onRefresh();// 发布一个 `ContextRefreshedEvent` 事件,表示上下文已经刷新完成this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));// 如果应用不是在原生镜像中运行,注册当前应用上下文,以便在 Beans View 中显示if (!NativeDetector.inNativeImage()) {LiveBeansView.registerApplicationContext(this);}
}
- 在初始化工作全部结束后,
spring
会发布一个ContextRefreshedEvent
事件,表示上下文已经刷新完成
因此我们可以写一个listener
来监听这个事件,并在刷新结束后执行一些操作:
@Component
public class MyListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {// 当容器启动完成并发布 ContextRefreshedEvent 事件时执行System.out.println("容器已经启动,我们可以做些初始化的操作");}
}
查看核心代码getBean()
public Object getBean(String name) throws BeansException { return this.doGetBean(name, (Class)null, (Object[])null, false);
}
继续向下看doGetBean()
,Spring框架中do开头的方法为具体的做事方法
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {// 转换 Bean 名称,name统一转化为beanName,因为name可能是别名String beanName = this.transformedBeanName(name);// 尝试从单例缓存中获取实例Object sharedInstance = this.getSingleton(beanName);Object beanInstance;// 如果单例实例存在并且没有传递构造参数if (sharedInstance != null && args == null) {// 检查并记录日志if (this.logger.isTraceEnabled()) {if (this.isSingletonCurrentlyInCreation(beanName)) {this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");} else {this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");}}// 获取 Bean 实例,可能是 FactoryBean 的对象beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);} else {// 检查原型模式下是否存在循环依赖,若存在则抛出异常if (this.isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 递归从父工厂中获取 Bean(如果存在父工厂且当前工厂中未定义此 Bean)//有点像双亲委派BeanFactory parentBeanFactory = this.getParentBeanFactory();if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {// 根据name获取beanName,如果name以&开头,就会返回&+beanNameString nameToLookup = this.originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {AbstractBeanFactory abf = (AbstractBeanFactory)parentBeanFactory;return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}// 根据类型或构造参数获取 Beanif (args != null) {return parentBeanFactory.getBean(nameToLookup, args);}if (requiredType != null) {return parentBeanFactory.getBean(nameToLookup, requiredType);}return parentBeanFactory.getBean(nameToLookup);}// 如果不是仅检查类型,将此 Bean 标记为已创建if (!typeCheckOnly) {this.markBeanAsCreated(beanName);}// 记录 Bean 实例化的性能指标StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name);try {// 根据需要的类型记录性能监控信息if (requiredType != null) {Objects.requireNonNull(requiredType);beanCreation.tag("beanType", requiredType::toString);}// 合并 Bean 定义信息RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);// 检查合并的 Bean 定义是否满足条件this.checkMergedBeanDefinition(mbd, beanName, args);// 判断当前创建的 Bean 是否有依赖项String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {// 检查是否存在循环依赖if (this.isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//不存在depends-on循环依赖就会进行注册this.registerDependentBean(dep, beanName);// 确保依赖项被实例化try {//递归实例化this.getBean(dep);} catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// 根据不同作用域实例化 Beanif (mbd.isSingleton()) {// 创建单例 Bean 并缓存// 通过getSingleton(beanName,singletonFactory)方法获取实例对象// 使用lambda表达式来实现匿名内部类,传入singletonFactory参数sharedInstance = this.getSingleton(beanName, () -> {try {// 核心方法,这里完成创建Bean对象(重点)return this.createBean(beanName, mbd, args);} catch (BeansException ex) {// 如果创建过程中发生异常,则会进行销毁this.destroySingleton(beanName);throw ex;}});//判断是否是BeanFactory还是普通的beanbeanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);//实例化多例bean//和单例bean的区别是不会存储到缓存中} else if (mbd.isPrototype()) {// 创建原型 BeanObject prototypeInstance;try {this.beforePrototypeCreation(beanName);prototypeInstance = this.createBean(beanName, mbd, args);} finally {this.afterPrototypeCreation(beanName);}beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);} else {// 实例化其他作用域的beanString scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");}Scope scope = (Scope)this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {// 从自定义作用域中获取 BeanObject scopedInstance = scope.get(beanName, () -> {this.beforePrototypeCreation(beanName);try {return this.createBean(beanName, mbd, args);} finally {this.afterPrototypeCreation(beanName);}});beanInstance = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);} catch (IllegalStateException ex) {throw new ScopeNotActiveException(beanName, scopeName, ex);}}} catch (BeansException ex) {// 捕获 Bean 创建过程中的异常并记录beanCreation.tag("exception", ex.getClass().toString());beanCreation.tag("message", String.valueOf(ex.getMessage()));this.cleanupAfterBeanCreationFailure(beanName);throw ex;} finally {// 结束性能监控beanCreation.end();}}// 将实例适配到所需类型return this.adaptBeanInstance(name, beanInstance, requiredType);
}
大致流程:
- 转换别名,获取能够解析的beanName
- 尝试从缓存中获取,获取到则返回该
bean
- 若缓存没有,则判断是否存在父工厂且本地工厂不存在该bean
- 满足则将由父工厂创建该
bean
- 满足则将由父工厂创建该
- 父工厂不存在则,由自己进行创建
- 先获取该
bean
的依赖项,然后循环通过getBean()
递归优先实例化 - 合并
bean
的定义,判断作用范围- 是单例的,调用
getSingleton()
过程中会进行缓存 - 是多例的,在
createBean()
过程中不会进行缓存 - 其他的自定义范围也会走
createBean()
- 是单例的,调用
- 先获取该
接下来看单例bean
的构建过程:
if (mbd.isSingleton()) {// 创建单例 Bean 并缓存// 通过 getSingleton(beanName, singletonFactory) 方法获取实例对象// 使用 lambda 表达式来实现匿名内部类,传入 singletonFactory 参数sharedInstance = this.getSingleton(beanName, () -> {try {// 核心方法,这里完成创建 Bean 对象(重点)return this.createBean(beanName, mbd, args);} catch (BeansException ex) {// 如果创建过程中发生异常,则会销毁该单例实例this.destroySingleton(beanName);throw ex;}});// 判断是否是 FactoryBean,如果是则调用 getObjectForBeanInstance 获取实际对象;// 否则直接返回单例 bean 实例beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
查看getSingleton
源码:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {// 确保 beanName 不为空Assert.notNull(beanName, "Bean name must not be null");// 加锁保证线程安全synchronized(this.singletonObjects) {// 从缓存中获取已创建的单例对象Object singletonObject = this.singletonObjects.get(beanName);// 如果缓存中没有该单例对象,则创建新实例if (singletonObject == null) {// 如果当前正在销毁单例对象,抛出异常禁止创建新单例if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)");}// 输出调试日志信息if (this.logger.isDebugEnabled()) {this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}// 在单例对象创建之前执行前置操作this.beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = this.suppressedExceptions == null;// 记录异常信息if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {// 使用 singletonFactory 创建单例对象singletonObject = singletonFactory.getObject();newSingleton = true;} catch (IllegalStateException ex) {// 如果出现异常,再次尝试从缓存获取单例对象singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}} catch (BeanCreationException ex) {// 在抛出异常之前,添加 suppressedExceptions 信息if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;} finally {// 清除 suppressedExceptions 记录if (recordSuppressedExceptions) {this.suppressedExceptions = null;}// 在单例对象创建之后执行后置操作this.afterSingletonCreation(beanName);}// 如果成功创建新单例,将其加入缓存if (newSingleton) {this.addSingleton(beanName, singletonObject);}}return singletonObject; // 返回单例对象}
}
这个方法首先会获取this.singletonObjects.get(beanName)
获取一个bean
而这个singletonObjects
其实就是一个Map
:
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
具体的实例化过程在singletonObject = singletonFactory.getObject();
这句话
在传参的时候,通过匿名内部类重写了,getObject()
方法,通过调用createBean(beanName, mbd, args);
来进行实例化
上面是单例bean
的实例化过程,可以看到最后会将单例对象做一个缓存。
下面看一下多例bean
的实例化:
else if (mbd.isPrototype()) { var12 = null; Object prototypeInstance; try { this.beforePrototypeCreation(beanName); prototypeInstance = this.createBean(beanName, mbd, args); } finally { this.afterPrototypeCreation(beanName); } beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
并没有调用getSingleton
,而是直接调用createBean(beanName, mbd, args);
,因此并没有缓存。
如何创建的对象呢?查看createBean()
:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {// 如果日志级别是 TRACE,则记录创建 Bean 的开始过程if (this.logger.isTraceEnabled()) {this.logger.trace("Creating instance of bean '" + beanName + "'");}// 克隆 BeanDefinition,如果需要,将解析后的类替换到克隆的定义中RootBeanDefinition mbdToUse = mbd;Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {// 创建一个新的 RootBeanDefinition,用于承载解析后的类mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}try {// 准备方法重写配置(如果有),用于支持动态代理、CGLIB等功能mbdToUse.prepareMethodOverrides();} catch (BeanDefinitionValidationException var9) {// 如果方法重写配置校验失败,抛出异常throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);}Object beanInstance;try {// 尝试通过 BeanPostProcessor 在实例化前返回一个实例beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);if (beanInstance != null) {// 如果提前生成了 Bean 实例,直接返回return beanInstance;}} catch (Throwable var10) {// 捕获实例化前的处理异常,包装成 BeanCreationExceptionthrow new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);}try {// 执行实际的 Bean 创建过程beanInstance = this.doCreateBean(beanName, mbdToUse, args);// 如果日志级别是 TRACE,记录创建完成的信息if (this.logger.isTraceEnabled()) {this.logger.trace("Finished creating instance of bean '" + beanName + "'");}// 返回创建完成的 Bean 实例return beanInstance;} catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {// 对隐式出现的单例异常和已有的创建异常直接抛出throw var7;} catch (Throwable var8) {// 捕获其他异常,包装为 BeanCreationException 并抛出throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);}
}
这段可以作为一个参考:
在使用某个遍历,可以做一个拷贝,然后操作这个局部变量。
局部变量天生局部线程安全的特性
// 克隆 BeanDefinition,如果需要,将解析后的类替换到克隆的定义中RootBeanDefinition mbdToUse = mbd;Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {// 创建一个新的 RootBeanDefinition,用于承载解析后的类mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}
实例化的核心代码:
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
doCreateBean
源码:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {// 定义一个 BeanWrapper 用于封装 Bean 实例BeanWrapper instanceWrapper = null;// 如果是单例 Bean,则尝试从缓存中获取实例包装对象if (mbd.isSingleton()) {instanceWrapper = (BeanWrapper) this.factoryBeanInstanceCache.remove(beanName);}// 如果缓存中没有实例包装对象,则通过创建新的 Bean 实例if (instanceWrapper == null) {instanceWrapper = this.createBeanInstance(beanName, mbd, args);}// 获取实例对象和类信息Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {// 设置目标类型到 Bean 定义中mbd.resolvedTargetType = beanType;}// 允许修改合并后的BeanDefinition,提供的扩展点synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);} catch (Throwable var17) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);}// 标记为已处理mbd.markAsPostProcessed();}}// 检查是否需要提前暴露单例(用于处理循环依赖)boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);if (earlySingletonExposure) {if (this.logger.isTraceEnabled()) {this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");}// 提前暴露单例,通过 ObjectFactory 提供早期引用this.addSingletonFactory(beanName, () -> this.getEarlyBeanReference(beanName, mbd, bean));}// 初始化暴露的对象Object exposedObject = bean;try {// 填充 Bean 的属性(依赖注入)this.populateBean(beanName, mbd, instanceWrapper);// 初始化 Bean,包括调用初始化方法和 BeanPostProcessor 的方法exposedObject = this.initializeBean(beanName, exposedObject, mbd);} catch (Throwable var18) {// 处理异常,并将其包装为 BeanCreationExceptionif (var18 instanceof BeanCreationException) {BeanCreationException bce = (BeanCreationException) var18;if (beanName.equals(bce.getBeanName())) {throw bce;}}throw new BeanCreationException(mbd.getResourceDescription(), beanName, var18.getMessage(), var18);}// 再次检查早期暴露的单例,处理循环依赖问题if (earlySingletonExposure) {Object earlySingletonReference = this.getSingleton(beanName, false);if (earlySingletonReference != null) {// 如果暴露的对象与当前 Bean 不一致,可能是因为包装问题,进行处理if (exposedObject == bean) {exposedObject = earlySingletonReference;} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {String[] dependentBeans = this.getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");}}}}try {// 注册销毁方法(如果必要)this.registerDisposableBeanIfNecessary(beanName, bean, mbd);// 返回最终暴露的对象return exposedObject;} catch (BeanDefinitionValidationException var16) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);}
}
BeanWrapper
是 Spring Framework 中的一个接口,定义在org.springframework.beans
包下。它是 Spring 的 Bean 操作工具之一,用于封装一个具体的 Java Bean,并提供对该 Bean 的属性进行操作的功能,包括属性的获取、设置和类型转换。
doCreateBean()
方法大致分为如下步骤:
- 实例化阶段:使用
BeanWrapper
对象进行包装,判断缓存是否存在,如果不存在,则实例化bean
对象。 BeanDefinition
后置处理:提供扩展点,允许在合并后的BeanDefinition
上进行修改。- 循环依赖处理:如果
Bean
是单例、支持循环引用,并且正在创建中,将对象放入singletonFactories
三级缓存。 - 依赖注入阶段:进行
Bean
的属性填充。 - 初始化阶段:初始化
Bean
对象。 - 处理循环依赖的提前暴露:如果之前进行了循环依赖的提前暴露,获取提前暴露的Bean引用,根据条件更新
Bean
。 - 注册需要销毁的
Bean
:根据需要,注册需要销毁的Bean
。
查看createBeanInstance
:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 获取 Bean 的类对象Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) // 检查类是否是 public&& !mbd.isNonPublicAccessAllowed()) { // 是否允许非 public 访问throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());} else {// 如果定义了自定义的实例供应商(Supplier),优先使用它来创建实例Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return this.obtainFromSupplier(instanceSupplier, beanName);} // 如果配置了工厂方法,使用工厂方法实例化 Beanelse if (mbd.getFactoryMethodName() != null) {return this.instantiateUsingFactoryMethod(beanName, mbd, args);} else {// 定义两个标志位boolean resolved = false; // 是否已经解析过构造函数boolean autowireNecessary = false; // 是否需要自动注入// 如果没有传递构造函数参数,尝试从缓存中获取构造函数解析结果if (args == null) {synchronized(mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}// 如果已经解析过构造函数,根据是否需要自动注入决定实例化策略if (resolved) {return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);} else {// 从 BeanPostProcessor 中确定可能的构造函数Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);// 如果没有明确的构造函数需要解析且没有构造函数参数,则使用默认构造函数if (ctors == null && mbd.getResolvedAutowireMode() != 3 // 非构造函数注入模式&& !mbd.hasConstructorArgumentValues() // 没有显式的构造参数&& ObjectUtils.isEmpty(args)) { // 参数为空ctors = mbd.getPreferredConstructors();return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);} else {// 使用自动注入策略的构造函数return this.autowireConstructor(beanName, mbd, ctors, args);}}}}
}
createBeanInstance()
方法大致做了如下工作:
- 获取并判断
Bean
类型:从BeanDefinition
中获取Bean
的类。判断如果Bean
类不是公共类且不允许访问非公共类,则抛出异常。 - 实例化
Bean
:如果存在instanceSupplier
,存在则直接获取实例。否则,根据工厂方法或构造方法实例化Bean。 - 判断是否已确定构造方法:如果已经确定构造方法,根据情况选择有参或无参构造方法。
- 推断构造方法:如果不确定构造方法,则获取Bean对应的所有构造方法,如果找到了进行创建Bean ,没有找到则会直接使用无参的构造方法完成Bean的初始化。
由此可知,createBeanInstance
方法负责解析Bean
类、选择构造函数、执行自动装配,最终创建Bean
实例并返回
然后接着看填充bean
和初始化bean
:
// 填充 Bean 的属性(依赖注入)
this.populateBean(beanName, mbd, instanceWrapper);// 初始化 Bean,包括调用初始化方法和 BeanPostProcessor 的方法
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
先看populateBean()
:
populateBean
方法是 Spring 框架的核心方法之一,用于为 Bean 设置属性值并执行相关的依赖注入逻辑。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// 如果 BeanWrapper 为 null,并且有属性值,则抛出异常if (bw == null) {if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Cannot apply property values to null instance");}// 如果没有属性值且 BeanWrapper 为空,直接返回return;}// 如果 Bean 不是合成的(非框架内部生成),并且存在 InstantiationAwareBeanPostProcessorif (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {// 遍历所有 InstantiationAwareBeanPostProcessorIterator<InstantiationAwareBeanPostProcessor> var4 =this.getBeanPostProcessorCache().instantiationAware.iterator();while (var4.hasNext()) {InstantiationAwareBeanPostProcessor bp = var4.next();// 如果任何一个 postProcessAfterInstantiation 方法返回 false,停止属性注入if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}// 获取定义中的属性值PropertyValues pvs = mbd.hasPropertyValues() ? mbd.getPropertyValues() : null;// 获取自动装配模式,1 = AUTOWIRE_BY_NAME, 2 = AUTOWIRE_BY_TYPEint resolvedAutowireMode = mbd.getResolvedAutowireMode();if (resolvedAutowireMode == 1 || resolvedAutowireMode == 2) {// 创建新的属性集合,复制原始属性值MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// 根据自动装配模式,执行按名称或按类型的依赖注入if (resolvedAutowireMode == 1) {this.autowireByName(beanName, mbd, bw, newPvs); // 按名称注入}if (resolvedAutowireMode == 2) {this.autowireByType(beanName, mbd, bw, newPvs); // 按类型注入}// 更新属性值为新生成的集合pvs = newPvs;}// 再次调用 InstantiationAwareBeanPostProcessor 处理属性if (this.hasInstantiationAwareBeanPostProcessors()) {if (pvs == null) {pvs = mbd.getPropertyValues();}// 遍历所有的 InstantiationAwareBeanPostProcessorPropertyValues pvsToUse;Iterator<InstantiationAwareBeanPostProcessor> var11 =this.getBeanPostProcessorCache().instantiationAware.iterator();while (var11.hasNext()) {InstantiationAwareBeanPostProcessor bp = var11.next();// 调用 postProcessProperties 方法,允许修改属性值pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {// 如果处理器返回 null,停止属性注入return;}pvs = pvsToUse; // 更新属性值}}// 检查依赖项(比如是否有未满足的强制依赖)boolean needsDepCheck = mbd.getDependencyCheck() != 0;if (needsDepCheck) {// 筛选需要检查依赖的属性描述符PropertyDescriptor[] filteredPds =this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);// 执行依赖检查this.checkDependencies(beanName, mbd, filteredPds, pvs);}// 将最终的属性值应用到 Bean 上if (pvs != null) {this.applyPropertyValues(beanName, mbd, bw, pvs);}
}
流程:
- 检查是否可以为 Bean 设置属性值:
- 如果
BeanWrapper
为null
且RootBeanDefinition
中存在属性值,则抛出异常。 BeanWrapper
是一个工具类,用于封装 Bean 实例并提供对其属性的访问。
- 如果
- 执行
InstantiationAwareBeanPostProcessor
的后处理器逻辑:- 调用所有实现了
InstantiationAwareBeanPostProcessor
的 BeanPostProcessor,依次执行其postProcessAfterInstantiation
方法。如果其中一个返回false
,则直接退出,不设置属性值。
- 调用所有实现了
- 根据自动装配模式进行注入:
resolvedAutowireMode
解析依赖注入的方式,将属性装配到PropertyValues
中- 如果自动装配模式为 byName 或 byType:
- byName:
根据属性名在 Spring 容器中查找对应的 Bean,并将其注入到目标属性中。 - byType:
根据属性的类型在 Spring 容器中查找匹配的 Bean。如果有多个符合的候选项,会报错。
- byName:
- 如果自动装配模式为 byName 或 byType:
- 再次调用
InstantiationAwareBeanPostProcessor
的逻辑:- 调用所有实现了
InstantiationAwareBeanPostProcessor
的postProcessProperties
方法,允许进一步修改或替换属性值。 - 如果任何一个处理器返回
null
,则直接退出。
- 调用所有实现了
- 执行依赖检查:
- 检查是否存在未满足的依赖,如果有未注入的属性(比如
@Required
注解标注的属性未赋值),则抛出异常。
- 检查是否存在未满足的依赖,如果有未注入的属性(比如
- 应用属性值:
- 使用
applyPropertyValues
方法设置注入好的属性值给BeanWrapper
,最终完成属性的填充。
- 使用
扩展:
InstantiationAwareBeanPostProcessor
是一个重要的扩展点,允许开发者在 Bean 实例化后对其属性进行额外的处理。
postProcessAfterInstantiation
:- 如果返回
false
,表示不再继续属性注入。
- 如果返回
postProcessProperties
:- 可以修改 Bean 的属性值,返回新的
PropertyValues
。
- 可以修改 Bean 的属性值,返回新的
接下来看初始化函数initializeBean
:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {// 调用 Aware 接口方法,例如 BeanNameAware、BeanFactoryAware 等,// 用于注入 Spring 容器或上下文信息到 Bean 中this.invokeAwareMethods(beanName, bean);// wrappedBean 是当前处理的 Bean 实例,初始化时可能会被替换为代理对象Object wrappedBean = bean;// 如果当前 Bean 不是 synthetic(非 Spring 内部 Bean),// 则调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法if (mbd == null || !mbd.isSynthetic()) {wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);}try {// 调用 Bean 的初始化方法,包括:// 1. 如果实现了 InitializingBean,则调用其 afterPropertiesSet 方法;// 2. 如果在配置中指定了 init-method,则调用指定方法this.invokeInitMethods(beanName, wrappedBean, mbd);} catch (Throwable ex) {// 如果初始化方法抛出异常,包装为 BeanCreationException 抛出throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null,beanName,ex.getMessage(),ex);}// 如果当前 Bean 不是 synthetic(非 Spring 内部 Bean),// 则调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法if (mbd == null || !mbd.isSynthetic()) {wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}// 返回最终处理后的 Bean 实例(可能是原始对象或代理对象)return wrappedBean;
}
initializeBean()方法大致做了如下工作:
Aware
接口回调:回调实现了AwareMethods
接口的Bean
。调用顺序依次为实现BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
接口的Bean
- 调用初始化前的前置处理器:调用
BeanPostProcessor
初始化前的方法,在初始化之前对Bean
进行增强处理。 - 调用初始化方法:进行调用Bean的初始化方法。
- 调用初始化后的后置处理器:最后,调用
BeanPostProcessor
初始化后的方法,在初始化之后对Bean进行处理,触发Bean的后置处理,AOP
代理对象也在该阶段产生(这里说法有些不严谨,在后续讲循环依赖时,会分析哪种情况下提前生成AOP代理对象)。
由此可知,initializeBean()
方法主要负责在Spring容器中初始化Bean
,包括回调Aware
接口、前置处理、初始化方法调用和后置处理等
查看初始化前的前置处理方法,其他的类似就不重复看了:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {// 初始化结果变量,用于存储经过处理器修改后的 Bean 实例Object result = existingBean;// 遍历所有注册的 BeanPostProcessorfor (Iterator var4 = this.getBeanPostProcessors().iterator(); var4.hasNext(); result = current) {// 获取当前的 BeanPostProcessor 实例BeanPostProcessor processor = (BeanPostProcessor) var4.next();// 调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法// 此方法会对当前 Bean 进行“初始化前”的处理Object current = processor.postProcessBeforeInitialization(result, beanName);// 如果某个处理器返回 null,直接终止后续处理并返回当前结果if (current == null) {return result; // 保留当前的 result,并终止循环}// 更新 result 为最新处理的 Bean 实例result = current;}// 返回最终处理后的 Bean 实例return result;
}
![[77dd5cbd97fd12160bdf44d954a1c5d6.png]]
第五章 循环引用
1、产生的问题
在写代码的时候,发现如下场景:
@Component
public class A {private B b;@Autowiredpublic A(B b) {this.b = b;}
}@Component
public class B {private A a;@Autowiredpublic B(A a) {this.a = a;}
}
启动工程会报以下的错误,A构造需要B,B构造需要A,循环依赖:
在代码中:
A
和B
通过构造函数互相依赖。A
的构造函数需要B
。B
的构造函数需要A
。
这种循环依赖会导致 Spring 在创建 Bean 的过程中无法完成依赖注入,因为:
- Spring 在实例化
A
时需要B
,而B
需要先被创建。 - 在尝试创建
B
时,又需要先创建A
。 - 这个过程会无限循环,最终抛出
BeanCurrentlyInCreationException
。
在Spring
中,通常Bean
对象设置属性有三种方式:
- 基于构造方法注入:
- 方式一:
@Component public class A {private B b;@Autowiredpublic A(B b) {this.b = b;} }@Component public class B {private A a;@Autowiredpublic B(A a) {this.a = a;} }
- 方式二:
public class A {private B b;public A(B b) {this.b = b;} }
xml
配置文件:<bean id="bBean" class="com.Guo.B"/><bean id="aBean" class="com.Guo.A"><constructor-arg ref="bBean"/> </bean>
- 基于
set
方法注入@Component public class A {private B b;@Autowiredpublic void setB(B b) {this.b = b;} }@Component public class B {private A a;@Autowiredpublic void setA(A a) {this.a = a;} }
- 基于属性注入
@Component public class A {@Autowiredprivate B b;}
上面三种属性注入情况,若产生循环依赖,实际上Spring
只能解决后两者,而基于构造方法注入产生的循环依赖,Spring
是处理不了的。
这里为什么处理不了基于构造方法注入产生的循环依赖呢?
- 其实Spring解决循环依赖的本质是将实例化和初始化分离,在实例化之后产生缓存,允许其它对象引用。
- 而构造方法注入,在解析构造方法参数时就会去创建引用对象,而当前类自身还没有完成实例化,如果引用对象又依赖当前对象,则会产生死循环,均无法创建。
2、基础解决方案
在之前讲解getBean()
代码的时候,在doCreateBean()
里提到一个早期暴露bean
的一个概念,代码如下:
// 检查是否需要提前暴露单例以解决循环依赖
boolean earlySingletonExposure = mbd.isSingleton() // 当前 bean 是否是单例模式&& this.allowCircularReferences // 是否允许循环依赖&& this.isSingletonCurrentlyInCreation(beanName); // 当前 bean 是否正在创建中if (earlySingletonExposure) {// 如果开启日志跟踪,输出调试信息if (this.logger.isTraceEnabled()) {this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");}// 提前将当前 bean 的工厂对象加入单例缓存this.addSingletonFactory(beanName, () -> {// 获取对当前 bean 的早期引用(如代理对象)return this.getEarlyBeanReference(beanName, mbd, bean);});
}
会判断bean
是否是单例、正在创建中且上下文支持循环引用,
- 满足则会将创建了的、未初始化和属性填充的==半创建
bean
==加入到缓存中
提前暴露的意义:
- 解决“构造器循环依赖”或“属性循环依赖”的问题。
- 避免在创建过程中的依赖失败。
具体的是addSingletonFactory()
方法:
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {// 检查传入的 singletonFactory 是否为空,防止非法参数Assert.notNull(singletonFactory, "Singleton factory must not be null");// 对 singletonObjects 进行同步,确保线程安全synchronized (this.singletonObjects) {// 如果当前单例对象缓存中尚未包含该 bean 的实例if (!this.singletonObjects.containsKey(beanName)) {// 将传入的单例工厂对象存入 singletonFactories 中this.singletonFactories.put(beanName, singletonFactory);// 如果 earlySingletonObjects 中有该 bean,移除它// 因为我们希望通过工厂方法动态生成早期引用,而不是使用缓存的实例this.earlySingletonObjects.remove(beanName);// 将 bean 名称记录到 registeredSingletons 中,表示已经注册过this.registeredSingletons.add(beanName);}}
}
上面的代码涉及到三级缓存:
/** 一级缓存,存储所有创建好的完整单例Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** 三级缓存,存储创建Bean的工厂对象 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** 二级缓存,存储未创建好的半成品单例Bean */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
- 一级缓存(
singletonObjects
):
存储所有已经创建好的完整单例Bean
,即我们常说的单例池缓存 - 二级缓存(
earlySingletonObjects
):
存储未创建好的半成品单例Bean,即我们常说的提前暴露缓存 - 三级缓存(
singletonFactories
):
存储创建Bean的工厂对象,即我们常说的工厂对象缓存
查看传入的bean
工厂getEarlyBeanReference()
方法:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {// 初始暴露的对象,默认是当前传入的 bean 实例Object exposedObject = bean;SmartInstantiationAwareBeanPostProcessor bp;// 如果 Bean 不是 synthetic(即不是 Spring 内部使用的特殊 Bean),// 且存在 InstantiationAwareBeanPostProcessor 类型的后置处理器if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {// 遍历缓存中的 SmartInstantiationAwareBeanPostProcessor 实例for (Iterator var5 = this.getBeanPostProcessorCache().smartInstantiationAware.iterator();var5.hasNext(); exposedObject = bp.getEarlyBeanReference(exposedObject, beanName)) {// 获取一个 SmartInstantiationAwareBeanPostProcessor 实例bp = (SmartInstantiationAwareBeanPostProcessor) var5.next();// 调用 getEarlyBeanReference 方法,允许后置处理器对暴露的 Bean 进行自定义处理// 处理后的 Bean 替换 exposedObject}}// 返回经过所有后置处理器处理后的暴露对象return exposedObject;
}
SmartInstantiationAwareBeanPostProcessor
的作用:
SmartInstantiationAwareBeanPostProcessor
是 BeanPostProcessor
的一种扩展,其主要功能是对 Bean 的早期引用进行额外的处理。
在循环依赖场景下,这个处理过程非常重要,比如:
- 创建代理对象(如使用 AOP 时,返回的是代理对象而不是原始对象)。
- 提前修改 Bean 的某些属性。
getEarlyBeanReference
方法:
getEarlyBeanReference
是 SmartInstantiationAwareBeanPostProcessor
的一个方法,允许自定义 Bean 的早期引用:
public Object getEarlyBeanReference(Object bean, String beanName) {// 生成缓存键,用于标识当前 Bean 的代理对象Object cacheKey = this.getCacheKey(bean.getClass(), beanName);// 将当前 Bean 暂存到 earlyProxyReferences 中,表明这个 Bean 将被代理或已被处理this.earlyProxyReferences.put(cacheKey, bean);// 检查是否需要代理当前 Bean,如果需要,则包装成代理对象返回return this.wrapIfNecessary(bean, beanName, cacheKey);
}
它可以返回原始的 Bean,或者是一个经过加工后的(例如,AOP 代理)的对象。
还记得在doGetBean()
时,会先从缓存中获取:
Object sharedInstance = this.getSingleton(beanName);
查看getSingleton()
源码:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 从单例对象缓存中获取单例对象Object singletonObject = this.singletonObjects.get(beanName);// 如果单例对象尚未创建且当前单例正在创建中if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {// 尝试从早期单例对象缓存中获取singletonObject = this.earlySingletonObjects.get(beanName);// 如果早期对象缓存也不存在且允许早期引用if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// 再次检查单例缓存,确保线程安全singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {// 再次检查早期单例对象缓存singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {// 获取对应的单例工厂ObjectFactory<?> singletonFactory = (ObjectFactory<?>) this.singletonFactories.get(beanName);if (singletonFactory != null) {// 通过工厂获取单例对象singletonObject = singletonFactory.getObject();// 将早期单例对象放入缓存this.earlySingletonObjects.put(beanName, singletonObject);// 移除单例工厂,避免重复创建this.singletonFactories.remove(beanName);}}}}}}return singletonObject;
}
最后,在创建好对象后,就不需要提前暴露,则需要将bean
从二级缓存删除,并放入一级缓存,下次获取直接从一级缓存获取即可。该处理逻辑位于getSingleton()
的末尾:
if (newSingleton) { this.addSingleton(beanName, singletonObject);
}
查看addSingleton()
源码:
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) { // 对单例对象缓存操作加锁,确保线程安全// 将完全初始化的单例对象添加到缓存this.singletonObjects.put(beanName, singletonObject);// 清理单例工厂缓存,防止后续再通过工厂创建对象this.singletonFactories.remove(beanName);// 清理早期单例对象缓存,标志该对象已完成初始化this.earlySingletonObjects.remove(beanName);// 记录该单例对象的名称,便于后续查找或管理this.registeredSingletons.add(beanName);}
}
3、有代理的循环依赖
上面我们分析到,似乎我们只需要在单例池缓存基础上额外加一层提前暴露缓存即可。
但是这里我们忘了一点,对象A在初始化阶段可能会产生AOP代理对象,最终放入单例池缓存的是A的代理对象,而对象A的属性注入阶段却在初始化阶段之前,这会造成放入提前暴露缓存的是对象A的普通对象,然后对象B注入的是对象A的普通对象,并不是对象A的代理对象,显然存在问题。
很明显,造成这样的问题是由于Bean
的生命周期,需要依次执行实例化、属性注入、初始化阶段。
在上一小节的暴露代码中:
if (earlySingletonExposure) {// 如果开启日志跟踪,输出调试信息if (this.logger.isTraceEnabled()) {this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");}// 提前将当前 bean 的工厂对象加入单例缓存this.addSingletonFactory(beanName, () -> {// 获取对当前 bean 的早期引用(如代理对象)return this.getEarlyBeanReference(beanName, mbd, bean);});
}
如果需要提前暴露,则会将这个暴露的bean
工厂加到三级缓存中。
执行流程:
- 实例化对象
A
,将A
的工厂放入到三级缓存做早期暴露 - 对象
A
依赖B
,则会在缓存中找B
- 从一级缓存➡二级缓存➡三级缓存的次序寻找
- 在找
B
时,发现缓存中都没有,则会创建B
- 实例化B
,实例化后将B
的工厂放入到三级缓存
-B
依赖于A
,则将A
注入到B
的工厂对象中
此时能够决绝循环依赖问题,但此时注入的都是原始的对象,而不是代理对象
在将A
注入到B
中,对调用工厂的getObject()
,其实就是调用getEarlyBeanReference(beanName, mbd, bean)
方法
这个方法有什么用呢?
想必通过上面分析的AOP代理场景下循环依赖解决,大家应该能反应过来。
没错,getEarlyBeanReference()
方法其实就是判断对象A
是否存在AOP
,如果对象A
存在AOP
,即需要提前创建代理对象A
,那么对象B
注入的就应该是代理后的对象A
,而不是普通对象A
。
我们进入getEarlyBeanReference()
方法源码看一下:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {// 初始暴露的对象,默认是当前传入的 bean 实例Object exposedObject = bean;SmartInstantiationAwareBeanPostProcessor bp;// 如果 Bean 不是 synthetic(即不是 Spring 内部使用的特殊 Bean),// 且存在 InstantiationAwareBeanPostProcessor 类型的后置处理器if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {// 遍历缓存中的 SmartInstantiationAwareBeanPostProcessor 实例for (Iterator var5 = this.getBeanPostProcessorCache().smartInstantiationAware.iterator();var5.hasNext(); exposedObject = bp.getEarlyBeanReference(exposedObject, beanName)) {// 获取一个 SmartInstantiationAwareBeanPostProcessor 实例bp = (SmartInstantiationAwareBeanPostProcessor) var5.next();// 调用 getEarlyBeanReference 方法,允许后置处理器对暴露的 Bean 进行自定义处理// 处理后的 Bean 替换 exposedObject}}// 返回经过所有后置处理器处理后的暴露对象return exposedObject;
}
在这段代码中会返回一个AOP
代理对象
因此,在实例化之后,会判断是否需要早期暴露,在暴露的过程中会将其放入到三级缓存,在通过工厂获取对象时,会判断是否需要生产代理对象,需要则返回一个代理对象。