SpringBoot -- 自动配置类AopAutoConfiguration解析注册BeanDefinition过程
Posted 做猪呢,最重要的是开森啦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot -- 自动配置类AopAutoConfiguration解析注册BeanDefinition过程相关的知识,希望对你有一定的参考价值。
在上一篇文章2.5.2.2节介绍了grouping.getImports()会获取所有符合的自动配置类名
·
然后循环遍历调用processImports来对自动配置类进行处理
本文以
AopAutoConfiguration
为栗子,对自动配置类的解析和注册再详细介绍一下
0. AopAutoConfiguration:
先大概说明下@ConditionOnXXX原理:
- 如果条件匹配,则条件结果对象ConditionOutcome的内部属性match为true,即该组件允许引入
@Configuration(proxyBeanMethods = false)
// 如果环境(配置文件)没有配置spring.aop.auto键值对,默认引入AopAutoConfiguration(因为 matchIfMissing = true,即上述match为true)
// 如果环境(配置文件)配置了spring.aop.auto键值对,如果value和havingValue相等,则上述match为true,即引入AopAutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
// 如果加载到Advice.class这个类,则上述match为true,就引入AspectJAutoProxyingConfiguration组件
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
// 如果环境(配置文件)没有配置spring.aop.proxy-target-class键值对,默认不引入JdkDynamicAutoProxyConfiguration
// 因为 matchIfMissing = false,即上述match为false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
// 如果环境(配置文件)没有配置spring.aop.proxy-target-class键值对,默认引入CglibAutoProxyConfiguration
// 因为 matchIfMissing = true,即上述match为true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
// 如果加载不到org.aspectj.weaver.Advice这个类,则上述match为true,就引入ClassProxyingConfiguration组件
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {
ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
通过上面条件注解的介绍,可以知道,在默认条件,即只引入
spring-boot-starter-aop
依赖,会引入三个组件Bean:
- AopAutoConfiguration
- AspectJAutoProxyingConfiguration
- CglibAutoProxyConfiguration
1. processGroupImports
在上一篇文章2.5.2.2节介绍处理自动配置类入口:循环遍历调用processImports来对自动配置类进行处理
处理AopAutoConfiguration时,processImports入参将配置类名封装成SourceClass
·
configurationClass为当前主配置类,也就是说通过该主配置类引入的AopAutoConfiguration
public void processGroupImports() {
... ... ...
try {
// 遍历递归处理解析的配置类名取处理配置类,包括嵌套引入的组件配置类;比如@Bean之类
// 入参将配置类名entry.getImportClassName()封装成ConfigurationClassParser.SourceClass
// 在内部processConfigurationClass方法入参会将SourceClass转换成ConfigurationClass
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
}
... ... ... //异常捕获抛出
});
}
}
1.1. processImports:
对于AopAutoConfiguration,只有@Configuration、@ConditionalOnProperty注解,直接调用processConfigurationClass去处理
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
... ... ...
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
... ... ...
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
... ... ...
}
else {
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 不属于以上两种类型,当作配置类处理入参将自身转换为ConfigurationClass
// 会将主配置类configClass添加到ConfigurationClass内部属性this.importedBy
// 这表明引入的所属关系,即AopAutoConfiguration是通过主配置类引入的
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
... ... ..
}
1.2. processConfigurationClass:
先进行@ConditionOnXXX条件匹配,匹配成功,则调用doProcessConfigurationClass解析嵌套类和自身
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
// shouldSkip主要时匹配@ConditionOnXXX的条件,匹配规则见上文,这里不跟源码了
// 对于AopAutoConfiguration,默认匹配成功引入该组件,则不跳过,即shouldSkip返回false
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
... ... ... // 当前AopAutoConfiguration配置类没有重复解析,省略代码
// 作为配置类,需要去解析是否有嵌套配置类,所以要封装成SourceClass
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
// 核心解析配置类方法,解析嵌套和自身
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
// 配置类解析完,添加到configurationClasses,用于上述判断重复解析,以及后续注册
this.configurationClasses.put(configClass, configClass);
}
1.3. doProcessConfigurationClass:
核心解析配置类方法,对于AopAutoConfiguration,不涉及@ComponentScan、@Import、@Bean等注解
·
所以此时只调用processMemberClasses进行嵌套类解析
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 内部嵌套类解析
processMemberClasses(configClass, sourceClass, filter);
}
... ... ... // AopAutoConfiguration不涉及 @ComponentScan、@Import等注解,直接省略
return null;
}
1.4. processMemberClasses:
会获取当前配置类的嵌套类,对于当前AopAutoConfiguration,会获取到:
- AspectJAutoProxyingConfiguration
- ClassProxyingConfiguration
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
Predicate<String> filter) throws IOException {
// 获取内部嵌套类并封装成SourceClass
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
// 判断嵌套类是否是配置类且不是自身
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
OrderComparator.sort(candidates);
// 循环解析符合的嵌套类
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
// 调用processConfigurationClass核心解析方法来解析
// 入参转换成ConfigurationClass,会将配置类configClass添加到ConfigurationClass内部属性this.importedBy
// 即表明内部嵌套类是通过AopAutoConfiguration引入的
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
finally {
this.importStack.pop();
}
}
}
}
}
1.5. 循环递归处理:
解析嵌套类就和解析AopAutoConfiguration一样,重复调用上述1.2 - 1.4的方法,整体如下:
递归循环处理后的结果就是会引入以下组件,并封装成ConfigurationClass类型
- AopAutoConfiguration
- AspectJAutoProxyingConfiguration
- CglibAutoProxyConfiguration
此外,在解析CglibAutoProxyConfiguration时,会引入AspectJAutoProxyRegistrar
·
在processImports方法会实例化该对象,并添加到CglibAutoProxyConfiguration
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
... ... ...
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
... ... ...
}
// AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar 条件成立
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
// 获取AspectJAutoProxyRegistrar实例对象,但为进行BeanDefinition注册
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
// 将AspectJAutoProxyRegistrar添加到所属配置类
// 后面注册BeanDefinition时会调用
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
... ... ...
}
2. loadBeanDefinitionsForConfigurationClass
在上一篇文章2.6节介绍了注册BeanDefinitions的入口,会循环调用
loadBeanDefinitionsForConfigurationClass
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 条件注解判断是否跳过这个配置类,详情可以参考文末参考链接3
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
// 如果跳过,Spring容器中移除bean的注册
this.registry.removeBeanDefinition(beanName);
}
// 从importRegistry 中也移除
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 如果这是一个通过import机制引入的配置类,也就是内部属性importedBy有所属的配置类
// 比如AopAutoConfiguration是主配置(启动)类引入的,则importedBy存的就是主配置类,上文1.1. 也介绍了
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 现在把配置类里面@Bean注解的方法作为bean定义注册到容器
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 从配置类导入的bean定义资源中获取bean定义信息并注册到容器,比如xml
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 从配置类导入的ImportBeanDefinitionRegistrar中获取bean定义信息并注册到容器
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
2.1. registerBeanDefinitionForImportedConfigurationClass
还是以AopAutoConfiguration为栗子,它是由主配置类引入的,所以条件成立会执行该方法
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
// 获取当前配置类元数据
AnnotationMetadata metadata = configClass.getMetadata();
// 构建BeanDefinition,为AnnotatedGenericBeanDefinition类型
// 会从元数据metadata获取className,然后给configBeanDef内部属性beanClass赋值
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
// 设置Scope,默认singleton
configBeanDef.setScope(scopeMetadata.getScopeName());
// 解析出beanName,如果是自动配置类,则为beanClass(上文有赋值)
// 如果是@Component(value = "beanName")这些注解定义有value ,会解析出value值给作beanName
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
// 这是会针对@Lazy、@Primary()、@DependsOn、@Role、@Description注解给当前BeanDefinition进行对应的赋值
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
// 将BeanDefinition封装成持有者对象BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 会调用registerBeanDefinition进行BeanDefinition注册,最终会将组件包括嵌套的beanDefinition添加到beanDefinitionMap,以及beanDefinitionNames
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
// 给当前配置类也设置beanName
configClass.setBeanName(configBeanName);
if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
最终会将组件包括嵌套的beanDefinition添加到beanDefinitionMap,以及beanDefinitionNames
2.2. loadBeanDefinitionsForBeanMethod
这个是处理@Bean的,其实也差不多,这里不展开介绍了
·
都是构建BeanDefinition,然后根据条件赋值,之后通过registerBeanDefinition注册进去
2.3. loadBeanDefinitionsFromRegistrars
@EnableAspectJAutoProxy注解会引入AspectJAutoProxyRegistrar,在上文1.5也提到
·
AspectJAutoProxyRegistrar重写了registerBeanDefinitions方法,这里便是调用重写后的方法注册
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 默认先创建一个AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,然后注册进去
// 注册的beanName为org.springframework.aop.config.internalAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 获取@EnableAspectJAutoProxy的键值对以上是关于SpringBoot -- 自动配置类AopAutoConfiguration解析注册BeanDefinition过程的主要内容,如果未能解决你的问题,请参考以下文章