扫描流程
入口是在 refresh 的 invokeBeanFactoryPostProcessors 流程中, 这里会拿到 ConfigurationClassPostProcessor 并由它来解析配置类, 在解析到 @ComponentScan 注解时, 根据解析获得的 basePackages 调用 ClassPathBeanDefinitionScanner.doScan 来扫描包路径. 拿到全部的 class 文件(Resource), 通过 ASM 技术解析每一个 Resource 文件获得其元数据信息 MetadataReader, 通过 excludeFilters 和 encludeFilters 和 @Conditional 条件的判断, 生成 ScannedGenericBeanDefinition 对象, 再通过独立和具体等条件的判断, 最终将通过判断的 BeanDefinition 加入结果集返回.
遍历结果集, 解析其 Scope 是单例还是原型, 获取并设置 beanName, 给 BeanDefinition 设置一些默认值, 解析 @Lazy, @Primary, @DependsOn 等, 最后再次判断 BeanDefinition 是否已经存在, 存在的话判断新旧是否兼容, 只有通过检测, 才会被注册到 beanDefinitionMap 中
创建流程
入口是在 refresh 的 finishBeanFactoryInitialization 流程中, 遍历所有的 BeanName, 根据 BeanName 拿到合并后(父子关系会继承一些配置)的 RootBeanDefinition, 校验非懒加载单例, 普通的直接调用 getBean 创建并存入单例池, FactoryBean 的先 getBean 创建 FactoryBean 本身, 存到单例池(BeanName 没有 & 符号), 再判断是否需要通过调用 getBean 的方式调用 getObject(getBean 内部会判断是否为 FactoryBean), FactoryBean.getObject 创建的 Bean 不是存到单例池, 而是存到 factoryBeanObjectCache Map 中, 其 Key(BeanName) 和 该FactoryBean 的相同
getBean 目标是返回一个 Bean, 其内部对 FactoryBean 有特殊的处理逻辑, 不管是从单例池中取出来的 Bean 还是刚刚创建好的 Bean, 都会走一波针对 FactoryBean 的特殊流程. 根据调用 getBean 的目的(如果传入的 name 前面有 & 则说明目的是获取 FactoryBean 本身)和 Bean 的实际类型, 把 Bean 分为三种情况来处理, 和 FactoryBean 无关的普通 Bean 直接返回, 要获取 FactoryBean 本身的返回其本身, 要获取 FactoryBean 的 getObject Bean 的, 则再调用 FactoryBean 的 getObject 方法获取 Bean(只经过实例化后(AOP)处理), 缓存起来, 然后再返回
接下来就是 getBean 了, 无 Bean 创建并返回, 有 Bean 直接返回. 首先解析 BeanName, 就是把别名转成 BeanName, 把 FactoryBean 的 & 开头的名字转成 BeanName, 根据 BeanName 到单例池中取, 如果取到了, 则针对 FactoryBean 的情况做下处理. 如果没有取到, 获取合并后的 BeanDefinition, 针对 @DependsOn 的 Bean 做 getBean, 根据 Scope 单例/原型/其他 分别调用 createBean 来创建 Bean, 单例的会多一步缓存到单例池的步骤, 原型的创建好直接返回(每次 getBean 都创建, 返回的不一样), 其他的先不管. 最终返回结果前, 判断拿到的 Bean 和需求的 Bean 类型是否匹配, 不匹配的能否转换
接下来就是 createBean 了, 大致流程如下
在 getBean 的最后一步, 就是判断当前 Bean 是否需要在容器关闭时执行指定的销毁方法, 该判断只针对单例和其他, 不支持原型. 某个 Bean 是 DisposableBean, 或有 @PreDestroy 注解的方法, 就会被认为是需要销毁, @PreDestroy 由 InitDestroyAnnotationBeanPostProcessor 这个 BeanPostProcessor 提供解析实现, 提供判断是否需要认定需要销毁. 然后把需要执行销毁的 Bean 都包装成为 DisposableBeanAdapter(实现了 DisposableBean, 有 destroy 方法) 并缓存起来, 其 destroy 方法可以针对各种情况的销毁方法做统一执行处理. 待容器关闭时, 直接调用缓存的 DisposableBeanAdapter 的 destroy 方法即可
然后是在容器关闭时, 调用 doClose 走销毁流程, 先把刚刚缓存的 DisposableBeanAdapter 都拿到, 调用其 destroy 方法执行通过各种方式定义的销毁方法, 然后再清空整个单例池. 在销毁 DisposableBeanAdapter 的时候, 会先根据 Bean 的互相依赖关系, 把所有依赖当前 Bean 的 Bean 优先销毁, 类似依赖注入的递归
Spring 以 Annotation 方式启动的入口如下, 新建 AnnotationConfigApplicationContext, 同时传入一个配置类, 内部调用无参构造函数, 给字段 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 赋值, 然后注册传入的配置类, 然后调用 Spring 模板方法 refresh 来启动整个容器
Spring 会先使用 ClassPathBeanDefinitionScanner 扫描指定包路径下的 BeanDefinition, 然后把其中非懒加载的单例 BeanDefinition 创建并注册成为 Bean 对象, 缓存在单例池(singletonObjects)中
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
public AnnotationConfigApplicationContext() {
// ...
this.reader = new AnnotatedBeanDefinitionReader(this);
// ...
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
虽然上面创建了一个 ClassPathBeanDefinitionScanner, 但是其仅仅是为了 AnnotationConfigApplicationContext 的下面这个构造器扫描 basePackages 服务的, 我们传入的是配置类而不是字符串数组, 所以我们并不会使用到这个 Scanner, 我们使用的是该类的另一个实例对象
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
Spring 以 Annotation 方式运行时扫描 BeanDefinition 是通过 ClassPathBeanDefinitionScanner.doScan() 来完成的. 执行的位置是在 refresh 方法的 invokeBeanFactoryPostProcessors(beanFactory) 流程中. 在这里会找到 ConfigurationClassPostProcessor(解析配置类), 调用其作为 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法来解析配置类, 流程包括解析 @ComponentScan 注解, 得到最终的 basePackages, 然后调用 Scanner.doScan 来扫描
扫描流程
核心就是 ClassPathBeanDefinitionScanner.doScan 方法中的 scanCandidateComponents 方法
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 从指定的包路径中扫描符合条件的 BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
// BeanDefinition 的后续赋值操作, 生成 beanName, 校验其他条件等
for (BeanDefinition candidate : candidates) {
// 解析 Scope, 单例/原型
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// beanName, AnnotationBeanNameGenerator.generateBeanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
// 给 BeanDefinition 赋一些默认值, 懒加载什么的
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析 @Lazy, @Primary, @DependsOn, @Role, @Description, 后面两个没有太大作用
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查容器中是否已经存在该 beanName, 如果存在且兼容, 则该 BeanDefinition 还是会被忽略
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册 BeanDefinitionHolder 中的 BeanDefinition, 即 BeanFactory 中的 beandefinitionMap
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
} else {
return scanCandidateComponents(basePackage);
}
}
在 doScan 中通过 findCandidateComponents 即可扫描到所有的 BeanDefinition, 其中有两个分支, 上面的分支是 Spring 提供的一种快速启动应用程序的方法, 原理就是创建一个索引文件, 告诉 Spring 哪些类是 BeanDefinition, 代替扫描的流程, 这样在类文件巨多的场景下能提升启动性能. 知道这个方法就可以了, 平时很少用到, 该方法的具体描述如下
虽然类路径扫描非常快, 但通过在编译时创建候选的静态列表, 可以提高大型应用程序(类非常多)的启动性能. 在此模式下, 应用程序的所有模块都必须使用此机制, 当 ApplicationContext 检测到此类索引时, 它将自动使用它, 而不是扫描类路径. 启用方式就是 pom 中引入 spring-context-indexer 依赖, 这个过程将需要一个名为 META-INF/spring.components 的文件, 并将其包含在jar包中. 如果在类路径中找到 META-INF/spring.components 时, 将自动启用索引. 也可以通过设置 spring.index.ignore 来配置是否启用索引
核心就是 ClassPathScanningCandidateComponentProvider#scanCandidateComponents
CachingMetadataReaderFactory 解析某个 class 文件得到 MetadataReader 对象, 是利用的 ASM 技术, 并没有加载这个类到 JVM. 并且最终得到的 ScannedGenericBeanDefinition 对象, 其 beanClass 属性存储的是当前类的全限定名, 而不是 class 对象(要拿到 Class 对象就必须得经过 JVM 加载). (beanClass 属性的类型是 Object, 即可以存储类的名字, 也可以存储 class 对象)
上面的流程是通过扫描拿到 BeanDefinition, 还可以通过 自定义 BeanDefinition, 解析 spring.xml 的 < bean>, @Bean 注解 等方式注册 BeanDefinition
拿到符合条件的 BeanDefinition 结果集后, 并不会直接注册, 还有后续流程, 如解析其 Scope 是单例还是原型, 获取并设置 beanName, 给 BeanDefinition 设置一些默认值, 解析 @Lazy, @Primary, @DependsOn 等, 最后再次判断 BeanDefinition 是否已经存在, 存在的话判断新旧是否兼容, 只有通过检测, 才会被注册到 beanDefinitionMap 中
Spring 实例化剩余非懒加载的 Bean 的入口是在 refresh 的 finishBeanFactoryInitialization 方法的 beanFactory.preInstantiateSingletons(), 最终调用的是 DefaultListableBeanFactory.preInstantiateSingletons
全部非懒加载的单例 Bean 将在这里被实例化, 包括普通 Bean 和 FactoryBean, FactoryBean 的 getObject Bean 默认是懒加载的, 不会在这里被调用 getBean 从而被实例化. 但是可通过让 FactoryBean 实现 SmartFactoryBean 接口, 复写 isEagerInit 方法并返回 true, 这样 FactoryBean 的 getObject Bean 也会在这里被调用 getBean 从而被实例化
在真正调用 getBean 之前还有一些流程如下
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 扫描 BeanDefinition 加入 beanDefinitionMap 时会把对应的 BeanName 也存到 List beanDefinitionNames 中
for (String beanName : beanNames) {
// Spring 支持配置父子关系的 BeanDefinition
// 子 BeanDefinition 可以先从父 BeanDefinition 中继承一些配置
// 然后子 BeanDefinition 再用自己的配置覆盖一遍
// 最终拿到的 BeanDefinition 才是用来创建 Bean 的 RootBeanDefinition
// RootBeanDefinition 就代表没有父的最终的 BeanDefinitionMap
// 注意一点, 合并是从父子 BeanDefinition 里拿到配置, 然后创建一个新的 RootBeanDefinition
// 合并后的 RootBeanDefinition 会存到 mergedBeanDefinitions 中用来创建 Bean
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非抽象, 是单例, 非懒加载 的 BeanDefinition 会被执行 实例化
// BeanDefinition.isAbstract, 非抽象的 BeanDefinition, 而不是指该 BeanDefinition 对应的 Class 是抽象的
// 通过 xml 配置的 BeanDefinition 可以配置成为抽象 abstract="true"
// 抽象的 BeanDefinition 往往用在父子 BeanDefinition 中
// 抽象的 BeanDefinition 不能生成 Bean, 但是可以被其他 BeanDefinition 继承其配置
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 如果是 FactoryBean 则走特殊逻辑
if (isFactoryBean(beanName)) {
// FactoryBean 的处理方式, 有如下两个步骤
// 先通过 &BeanName 获取到 FactoryBean 本身, 缓存到单例池, 名称是 BeanName, 类型是 FactoryBean
// 再通过 BeanName 获取到 getObject 的 Bean, 缓存到 factoryBeanObjectCache 中, 名称同样是 BeanName, 类型是对应的类型
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
// 实现了 SmartFactoryBean 接口的 FactoryBean, 覆盖了 isEagerInit 方法并返回 true, 才会在这里调用其 getObject 方法
if (isEagerInit) {
// 调用 FactoryBean 的 getObject 方法来创建 Bean
getBean(beanName);
}
}
} else {
// 直接创建 Bean
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// Bean 生命周期中的 初始化后 流程指的并不是这里
// 所有非懒加载的单例 Bean 创建完之后
for (String beanName : beanNames) {
// 从单例池 singletonObjects 拿到单例 Bean
Object singletonInstance = getSingleton(beanName);
// 如果该单例 Bean 实现了 SmartInitializingSingleton 接口, 则调用其 afterSingletonsInstantiated 方法
// 注意是所有非懒加载的单例 Bean 创建完缓存好之后, 才会再遍历调用所有单例 Bean 的这个方法
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
但是在实例化前还需要合并 BeanDefinition, Spring 支持配置父子关系的 BeanDefinition, 先创建一个全新的 RootBeanDefinition, 先从父 BeanDefinition 中继承一些配置, 然后再用子 BeanDefinition 的配置覆盖一遍, 最终拿到的 RootBeanDefinition 才是用来创建 Bean 的 BeanDefinition, 该 BeanDefinition 会被缓存到 mergedBeanDefinitions 中, getBean 的时候从这里拿
父子 BeanDefinition 使用的比较少, 知道这个点就行了, 举个例子: < bean> 里面的 parent 配置用来指向父 Bean
实现了 FactoryBean 接口的 Bean, 这样的 Bean 它本身是一个 Bean, FactoryBean 有一个 getObject 方法, 也能创建 Bean, 且也会被 Spring 管理起来(不是放在单例池, 而是在 factoryBeanObjectCache). 需要注意的是, 通过 getObject 创建的 Bean 没有经过 Spring 创建 Bean 的全部常规流程, 只会经过 初始化后(AOP) 流程, 没有 依赖注入 流程, 所以内部如果有其他字段, 是不会被执行注入的
通过 FactoryBean 名称获取到的 Bean 是 getObject 方法创建并被 Spring 管理的 Bean, 而通过 & 符号加 FactoryBean 名称获取到的 Bean 则是 FactoryBean 本身. 例如有如下配置, 通过 getBean(“userFactoryBean”) 获取到的是 User, 通过 getBean(“&userFactoryBean”) 获取到的则是 UserFactoryBean
@Component
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
FactoryBean 本身会被存到单例池 singletonObjects 中, 而 FactoryBean 的 getObject 创建的 Bean 则会被存到 factoryBeanObjectCache 中, 两者的名称都是 FactoryBean 本身的 BeanName, 只是在 getBean 的时候, 会根据是否有 & 符号前缀做特殊的处理
FactoryBean 有一个子接口 SmartFactoryBean, 覆盖其 isEagerInit 方法并返回 true, 则在创建非懒加载的全部单例 Bean 的时候会调用 FactoryBean 的 getObject 方法创建对应 Bean, 默认不是在这个时候创建 getObject 的 Bean
首次调用 getBean 会走创建 Bean 的流程, 然后缓存到单例池(FactoryBean 的 getObject Bean 会缓存在 factoryBeanObjectCache), 后续再次调用就会从缓存中拿
Spring 支持给 BeanName 起别名, 支持给别名再起别名, 在 BeanFactory 中有一个 aliasMap, 存放别名与 Name 的印射, 可通过别名获取到 BeanName 或者另一个别名, getBean 的时候, 先假设 name 是别名, 从 aliasMap 中获取, 将获取到的结果继续获取, 直到不存在, 说明此时的 name 就是 BeanName 了
getBean(beanName, Class< T>), 同时传入了 BeanName 与 Type, 流程同样是根据 BeanName 找到 Bean, 然后判断 Bean 类型与给定的 Type 是否匹配, 能否转换, 否则报错. 并不是按照传入的 type 去单例池中找这种类型的 Bean
createBean, 创建 Bean
在创建 Bean 的最后一步, 就是把最终需要执行销毁的 Bean 额外缓存起来, 最终销毁的时候, 统一执行销毁方法, 其位置是在 org.springframework.beans.factory.support.AbstractBeanFactory#registerDisposableBeanIfNecessary
触发 Bean 销毁的入口在 org.springframework.context.support.AbstractApplicationContext#doClose, 内部有一个流程就是销毁所有单例 Bean, 即单例池也会被清空, 只不过需要执行销毁逻辑的 Bean 会先一步执行销毁方法
getBean 的最后一步, 把所有需要执行销毁逻辑的 Bean 都包装成了一个 DisposableBeanAdapter, DisposableBeanAdapter 实现了 DisposableBean 接口, 有 destroy 方法. 定义销毁逻辑的方式有很多, 如实现 DisposableBean 接口, 实现 AutoCloseable 接口, 用 @PreDestroy 注解某个/些方法, 在 BeanDefinition 中指定 destroyMethodName 为具体的某个方法, 在 BeanDefinition 中设置 destroyMethodName 为 (inferred) 且存在 close / shutdown 方法, 在 Bean 被包装为 DisposableBeanAdapter 的时候, 会把根据不同情况调用不同销毁方法的逻辑封装到 DisposableBean 指定的 destroy 方法中, 最后销毁时只需要调用 DisposableBeanAdapter 的 destroy 就可以适配到各种具体的销毁方式