核心的后置处理器:ConfigurationClassPostProcessor
上一篇文章说道除了使用AnnotationApplicationContext对象手动添加的BeanDefinitionRegistryPostProcessor之外,首先回调的就是ConfigurationClassPostProcessor对象。
public class ConfigurationClassPostProcessor implements
BeanDefinitionRegistryPostProcessor,PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
// 实现自BeanDefinitionRegistryPostProcessor接口
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry){
// 解析配置类(@Import @ImportResource @ComponentScan ...)
processConfigBeanDefinitions(registry);
}
// 实现自BeanFactoryPostProcessor
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 通过用cglib增强配置类,准备在运行时为bean请求提供服务。后面详细解释
}
}
在此之前要先了解几种数据结构
ClassMetadata
public interface ClassMetadata {
// Return the name of the underlying class.
String getClassName();
// 是否是一个接口
boolean isInterface();
// 是否存在注解
boolean isAnnotation();
// 是否被 abstract 标记
boolean isAbstract();
// 返回这个类是不是基础类,既不是接口,也不是抽象类
boolean isConcrete();
// 返回这个类是否被final标记
boolean isFinal();
// 判断一个类是否独立(是否是一个顶部类 或者 静态内部类)
boolean isIndependent();
// 返回类中是否存在静态内部类、非静态内部类或者本地类
boolean hasEnclosingClass();
}
在Spring中将类划分为5种
public class ClassTypeTest {
public class InnerClass{
}
public static class NestedClass{
}
public static void main(String[] args) {
class LocalClass{
}
new Thread(() -> {
System.out.println("anonymous class");
}).start();
}
}
- ClassTypeTest => top level class 顶部类
- NestedClass => nested class 静态内部类
- InnerClass => inner class 非静态内部类
- LocalClass => local class 在方法中定义的类
- AnonymousClass=> anonymous class 匿名类
AnnotationMetadata
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
// 获取类上所有注解的类型名称
Set getAnnotationTypes();
// 获取类上指定注解的元注解,name是全类名
Set getMetaAnnotationTypes(String annotationName);
// 断定一个类上是否存在注解
boolean hasAnnotation(String annotationName);
// 断定一个类上的注解是否存在指定的元注解
boolean hasMetaAnnotation(String metaAnnotationName);
// 断定一个类中是否存在指定注解的方法
boolean hasAnnotatedMethods(String annotationName);
// 拿到类中标注了指定注解的所有方法
Set getAnnotatedMethods(String annotationName);
}
ConfigurationClass
final class ConfigurationClass {
/** 注解元信息 */
private final AnnotationMetadata metadata;
/** 类的资源标识 class文件路径 classLoader */
private final Resource resource;
/** bean名称 */
private String beanName;
/** 被引入的ConfigurationClass */
private final Set importedBy = new LinkedHashSet<>(1);
/** 内部的bean方法 */
private final Set beanMethods = new LinkedHashSet<>();
/** import导入的资源集合 */
private final Map> importedResources =
new LinkedHashMap<>();
/** import导入的 BeanDefinitionRegistrar 集合 */
private final Map importBeanDefinitionRegistrars =
new LinkedHashMap<>();
/** 需要跳过的beanMethod*/
final Set skippedBeanMethods = new HashSet<>();
}
ConfigurationMethod 和 BeanMethod
abstract class ConfigurationMethod {
/** 方法上注解的信息 */
protected final MethodMetadata metadata;
/** 方法所在类的配置类信息 */
protected final ConfigurationClass configurationClass;
}
final class BeanMethod extends ConfigurationMethod {
public BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
super(metadata, configurationClass);
}
}
解析配置类
解析流程:
- 获取是刷新前注入容器中的bdName(spring内部的+实例化context时传入的)
- 为这些bd设置标记 full or lite,如果没有这个标记的话,这个bd就不会当成一个配置类来解析
- 判断是否已经处理过了
- 处理Component注解 -> 处理内部类
- 处理PropertySources注解
- 处理ComponentScans和ComponentScan注解 -> include/exclude + doScan -> 将bd放入容器
- 处理Import注解,只是找出来
- 处理ImportResource注解
- 处理方法上的Bean注解
- 处理这个配置类接口的默认方法
- 处理这个配置类的父类
- 处理 DeferredImportSelector 导入了的类
- 处理 import导入的类、importSelector 导入的类、配置类的@Bean、扫描类的@Bean
上述的流程中用到了很多递归和循环,我们只需要关注主要的流程:
1、扫描出来的类什么时候放入容器中
2、Import的处理流程
3、@Bean处理(static @Bean和member @Bean)
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List configCandidates = new ArrayList<>();
// 返回的是容器刷新前注入的bean定义对象
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 这个if是来检查这个bean定义中是否已经被标注了full或者lite
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
// 如果已经被标记了,就不会去再次解析它
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// bean定义和beanName组合为一个holder放入list中
// 这里放入的一般是我们手动在 context 注册的,因为这时还没有扫描包
// demo中就只有注册的 appConfig 配置类
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果没有找到配置类就直接返回
if (configCandidates.isEmpty()) {
return;
}
// 排序
// 获取beanName的生成器,可以是实现 BeanNameGenerator 接口去自定义beanName
// 检查环境 省略不重要代码
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 存放候选的bean定义对象
Set candidates = new LinkedHashSet<>(configCandidates);
// 存放已经处理的配置类 ConfigurationClass
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 把候选的bean定义对象都传入到了 parse 方法中
parser.parse(candidates);
/**
验证
1、验证我们的 @Configuration 注解类是不是final的,如果是final就不能被cglib代理,所以在这里验证
2、验证方法是不是静态方法,如果是静态方法那么无需验证 立即返回
3、如果这个方法所在的类是一个 @Configuration 类,必须保证这个类的这个方法是可以被重写的,需要在cglib代理中重写
*/
parser.validate();
Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 去重
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 处理 configurationClasses 和 importBeanDefinitionRegistrars
// 扫描出来的类并不在这里处理,在扫描出来的时候已经加入到了bd Map中了
// 这里主要处理 import导入的类、importSelector 导入的类、配置类的@Bean、扫描类的@Bean
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
}
while (!candidates.isEmpty());
}
解析ComponentScan
processConfigBeanDefinitions
=> ConfigurationClassParser#parse
=> ConfigurationClassParser#parse(AnnotationMetadata, String)
=> ConfigurationClassParser#processConfigurationClass
=> ConfigurationClassParser#doProcessConfigurationClass
// doProcessConfigurationClass
// 重要的对象:componentScanParser
// 拿到了注解中配置的所有包名
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator
.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// 这个class被 @ComponentScan 注解了,那么立即执行扫描
Set scannedBeanDefinitions =
this.componentScanParser
.parse(componentScan, sourceClass.getMetadata().getClassName());
// 执行到这里,所有的 bd 都被扫描到了 scannedBeanDefinitions 中
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition()
.getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// Configuration Bean Component ComponentScan Import ImportResource
// 出现以上注解会继续调用 processConfigurationClass 方法 262行
// 继续判断这个类是否存在
// @PropertySources @ComponentScans @Import @ImportResource @Bean
// 所以每一个扫描出来的类都会进行整个流程的判断
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
componentScanParser对象的实例化,是在ConfigurationClassPostProcessor的postProcessBeanFactory方法中,在这个方法中实例化了一个ConfigurationClassParser对象,用于解析配置类。
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 构建了componentScanParser和conditionEvaluator
public ConfigurationClassParser(...) {
this.componentScanParser = new ComponentScanAnnotationParser(
environment, resourceLoader, componentScanBeanNameGenerator, registry);
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
ConfigurationClassParser#parse
// 扫描包下面的类,这个方法只是做一些扫描之前的准备工作,比如beanName生成、需要排除的类、是否懒加载、作用域、获取基本包...
// @param componentScan ComponentScan注解的信息,注解的属性值集合
// @param declaringClass 注解了@ComponentScan 的类的全称
public Set parse(AnnotationAttributes componentScan, final String declaringClass) {
// 1、作用域代理模式 在@ComponentScan注解里配置 不写默认为default
// 2、resourcePattern = **/*.class
// 3、include和exclude
// 4、是否是懒加载,默认是false
// 5、获取componentScan中配置的包数组
// 如果scan中配置的是class,则将class的包名放入扫描包的数组中
// 如果没有配置basePacke,则会将当前class的包名作为 basePackage
// 6、开始扫描
}
开始扫描
protected Set doScan(String... basePackages) {
Set beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 完成了包的扫描,返回包下所有的需要spring实例化的bd
// 配置top.gmfcj => classpath*:top/gmfcj/**/*.class => 获取对应所有的class文件在下面的resources中
// 使用ASM技术获取class
Set candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 解析scope属性
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 先判断注解上有没有beanName,有设置beanName,没有就将类名小写设置为beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
// 如果这个bd是 AbstractBeanDefinition 设置默认值比如 lazy init destroy
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
// 注解bean,进步获取一些注解 从bd的getMetadata()中获取 Lazy primary DependsOn Role Description
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils
.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 这个if是判断扫描出来的这个 candidate 是否在bdmap中存在了
if (checkCandidate(beanName, candidate)) {
// 不存在则会将这个 candidate 注册到bdmap中
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 生成代理对象
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册到bdmap中 注册的是代理对象还是真实的对象是根据每一个类的配置@Scope,如果没有配置代理的方法,默认是不会创建代理对象的
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
ScopedProxyMode:指定bean对象的代理类型
没有被切面织入,没有@Configuration注解,没有指定Cglib代理的类,Spring不会为这个类生成代理对象
被切面织入的类会在bean对象创建完成的最后一步生成代理对象(AbstractAutowireCapableBeanFactory#initializeBean=>applyBeanPostProcessorsAfterInitialization)
只要指定了Cglib代理,都会使用Cglib代理生成bean对象@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public enum ScopedProxyMode {
// 默认值,一般都是NO,除非在一些注解中指定了默认值比如:ComponentScan
DEFAULT,
// 不创建作用域代理
NO,
// 创建一个实现目标对象类公开的所有接口方法的JDK动态代理
INTERFACES,
// 创建一个基于类的代理(使用CGLIB)
TARGET_CLASS;
}
如果设置了代理,代理的逻辑
// ScopedProxyUtils#createScopedProxy
// proxyTargetClass=true:表示使用cglib false:使用jdk动态代理
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,BeanDefinitionRegistry registry, boolean proxyTargetClass) {
BeanDefinition targetDefinition = definition.getBeanDefinition();
String targetBeanName = getTargetBeanName(originalBeanName);
// 新的bd中的class已经指向了ScopedProxyFactoryBean这个类的class
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
// 设置目标bdr
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
// 设置原始的bd
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
// 将目标对象注册到容器中
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// 返回代理对象的bdr
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
解析Import
在处理Import的时候要分为三种情况
- Import一个类
- Import一个Selector
- Import一个Registrar