SpringBoot自动装配详解

Spring Boot自动装配

开篇

  1. @Import注解
    如果我们在项目中不同的模块提供多个spring bean配置,则@Import注释将非常有用。在这种情况下,最好将所有这些配置导入到单个配置类中,以便通过引用多个配置类来创建bean时不会产生任何混淆。Spring中的@Import注释允许从另一个配置类加载bean定义,将多个配置类导入单个应用程序配置非常容易,这里不过多篇幅讲解@Import

  2. @Enable注解驱动,对配置进行自动配置。

    • 通过ConfigurationClassParser类对标记为@Configuration注解的类进行解析。
    • 然后通过解析@Import注解进行自动导入配置,@Import支持以下三种方式解析。
      • 直接解析配置类@Configuraion
      • ImportSelector接口(Spring 4.0后增加了DeferredImportSelector继承自ImportSelector,两者的区别是ImportSelectorDeferredImportSelector先执行解析)
      • ImportBeanDefinitionRegistrar动态注册Bean的方式
  3. @Conditional条件注解,以及常见的Spring Boot常见条件注解

  4. 源码分析

引用例子抛出问题

@SpringBootApplication中包括@EnableAutoConfiguration注解,@Enable驱动,此时我们可能会想以下几个问题:

  1. @Enbale的主要作用是什么?
  2. 配置类是如何导入的?
  3. 配置类又是如何被解析的?
  4. 配置类导入方式是以什么方式进行导入的?

接下来我们带着问题看以下内容

@Enable 模块驱动

通过观察这些@Enable*的源码,我们发现所有注解都有一个@Import注解,@Import是用来导入配置类的,这就意味着这些自动开启的实现其实是导入一些自动配置的Bean。

  1. 直接导入配置类
    1
    2
    3
    4
    5
    6
    7
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Import(SchedulingConfiguration.class)
    @Documented
    public @interface EnableScheduling {

    }

直接导入配置类SchedulingConfiguration,这个类注解了@Configuration注解,且注册了一个scheduledAnnotationProcessor的Bean,源码如下:

1
2
3
4
5
6
7
8
9
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
  1. ImportSelector接口,实现该接口。

    根据条件选择配置类,通过选择的方式进行选择配置类。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AsyncConfigurationSelector.class)
    public @interface EnableAsync {
    Class<? extends Annotation> annotation() default Annotation.class;
    boolean proxyTargetClass() default false;
    AdviceMode mode() default AdviceMode.PROXY;
    int order() default Ordered.LOWEST_PRECEDENCE;
    }

AsyncConfigurationSelector通过条件来选择需要导入的配置类,AsyncConfigurationSelector实现了ImportSelector,这个接口需要重写selectImports方法,在此方法内进行事先条件判断。此例中,若adviceMode为PROXY,则返回ProxyAsyncConfiguration这个配置类;若为ASPECTJ则返回AspectJAsyncConfiguration配置类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
  1. ImportBeanDefinitionRegistrar接口,动态注册Bean
    1
    2
    3
    4
    5
    6
    7
    8
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;
    }

AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar接口的作用是在运行时自动添加Bean到已有的配置类,通过重写方法:

1
2
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)

其中,AnnotationMetadata参数用来获取当前配置类上的注解,BeanDefinitionRegister参数用来注册Bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}

总结:通过上述内容的描述可以清晰的看到@Enable注解回答了以下两个问题

  1. @Enable主要作用是导入配置
  2. @Enable导入配置的方式
    • 直接导入配置类,通过@Configuraion注解加持的配置类
    • 继承ImportSelector接口
    • 继承ImportBeanDefinitionRegistrar接口
  3. 配置类是通过上述三种方式进行导入
    • 直接导入配置类的方式很容易理解
    • ImportSelector接口方式程序又是如何进行解析的呢?请看下文内容。
    • ImportBeanDefinitionRegistrar接口又是如何进行解析?

Spring Boot条件注解讲解

  1. 常用相关条件注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @ConditionalOnBean              // 配置了某个特定Bean
    @ConditionalOnMissingBean // 没有配置特定Bean
    @ConditionalOnClass // classpath有指定类
    @ConditionalOnMissingClass // classpath没有指定类
    @ConditionalOnExpression // 给定的Spring Expression Language(SpEL)表达式计算结果为true
    @ConditionalOnJava // Java的版本匹配特定值或某一个范围值
    @ConditionalOnJndi // 参数中给定的JNDI位置必须存在一个,如果没有给参数,则要有JNDI InitialContext
    @ConditionalOnProperty // 指定的配置属性要有一个明确的值
    @ConditionalOnResource // Classpath里有指定资源
    @ConditionalOnWebApplication // 这是个Web应用程序
    @ConditionalOnNotWebApplication // 这不是个Web应用程序
  2. 条件注解@Conditional

    @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。通过一个源码我可以清晰的看到上面Spring Boot的源码都是采用条件注解。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional(OnBeanCondition.class)
    public @interface ConditionalOnBean {
    Class<?>[] value() default {};
    String[] type() default {};
    Class<? extends Annotation>[] annotation() default {};
    String[] name() default {};
    SearchStrategy search() default SearchStrategy.ALL;
    Class<?>[] parameterizedContainer() default {};
    }

@Conditional中有一个OnBeanCondition的条件类,条件类最终继承关系如下图所示:
OnBeanCondition继承关系
可以清晰的看到他最后继承自Condition接口

1
2
3
4
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

接口中包含一个matches方法,有两个参数一个是ConditionContext包含了获取环境变量信息,Bean信息,类加载器的贵相关信息,AnnotatedTypeMetadata获取注解的信息。通过该方法返回true和false来表明是否加载当前Bean信息。

Spring Boot添加了很多注解,主要分类以下六大类内容:

  1. Class条件
  2. Bean条件
  3. Property条件
  4. Resource条件
  5. Web应用程序条件
  6. SpEL表达式条件

自动化配置

  1. resource下添加META-INF文件,文件下添加spring.factories文件,如下图所示:

    spring.factories

    以Mybatis自动配置为主进行讲解,里面内容如下所示:

    1
    2
    3
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

我们可以看到里面是通过EnableAutoConfiguration这个注解来进行自动装配,也就是说添加了当前注解的类它会扫面spring.factorie文件下所有关于EnableAutoConfiguration指定类的全名称,然后进行自动化配置。

  1. EnableAutoConfiguration注解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    //排除Class类对象。
    Class<?>[] exclude() default {};
    //排除类名称。
    String[] excludeName() default {};
    }

EnableAutoConfiguration中添加了@Import注解,注解中包含AutoConfigurationImportSelector类,这个类继承自DeferredImportSelector接口,而它又继承自ImportSelector接口,这就说明他是通过ImportSelector的方式来完成自动化配置。

AutoConfigurationImportSelector继承关系

  1. ConfigurationClassParser类解析@Configuration标记的类

    • 主要作用:首先为什么要先说ConfigurationClassParser类,因为Spring的工具类ConfigurationClassParser用于分析@Configuration注解的配置类,产生一组ConfigurationClass对象。

    • 分析过程:

      • ConfigurationClassParser类的调用是由ConfigurationClassPostProcessor,而ConfigurationClassPostProcessor是继承自BeanDefinitionRegistryPostProcessor接口,它又继承自BeanFactoryPostProcessor接口,它会在容器启动过程中,应用上下文执行各个BeanFactoryPostProcessor时被执行。
      • BeanFactoryPostProcessor调用过程:Spring Boot 应用中在ApplicationContext对象创建时,会调用 AnnotationConfigUtils.registerAnnotationConfigProcessors() 注册这个BeanFactoryPostProcessor。执行时会调用postProcessBeanDefinitionRegistry方法,该方法中调用了该类中的processConfigBeanDefinitions方法来调用ConfigurationClassPostProcessor类的parse方法来进行解析@Configuration注解加载的类信息,以及调用BeanFactoryPostProcessorpostProcessBeanFactory()方法。
      • 分析过程会接受一组配置类(调用者已知其是配置类,通常就一个),从它开始分析所有关联的配置类
      • 分析过程主要是递归分析配置类的注解@Import,配置类内部嵌套类,找出其中所有的配置类,然后返回这组配置类

    ConfigurationClassPostProcessor继承关系:

    ConfigurationClassPostProcessor继承关系

    ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    int registryId = System.identityHashCode(registry);
    if (this.registriesPostProcessed.contains(registryId)) {
    throw new IllegalStateException(
    "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    }
    if (this.factoriesPostProcessed.contains(registryId)) {
    throw new IllegalStateException(
    "postProcessBeanFactory already called on this post-processor against " + registry);
    }
    this.registriesPostProcessed.add(registryId);
    //处理Config配置Bean。
    processConfigBeanDefinitions(registry);
    }

processConfigBeanDefinitions方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//标记为@Configuration候选类
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//从容器中获取已经标记为Bean的候选配置类名称。
String[] candidateNames = registry.getBeanDefinitionNames();

for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//如果当前类标记为@Configuration注解添加到候选类集合中。
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}

// 没有@Configuration注解的类直接返回。
if (configCandidates.isEmpty()) {
return;
}

// 根据@Order的value来进行排序。
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});

//获取生成策略包括@ComponentScan和@Import的范围。
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}

if (this.environment == null) {
this.environment = new StandardEnvironment();
}

//解析每一个标记@Configuration注解的类。
//首先构造ConfigurationClassParser类。
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);

// 因为不清楚候选是否确实是配置类,所以使用BeanDefinitionHolder类型记录
// 这里初始化为方法开始时容器中注解了@Configuration的Bean定义的集合
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 这里记录已经解析的类。
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//解析配置文件,如果是标记为@Component注解的直接解析成bean,如果标记为@Import注解的将解析三种类型的类文件进行循环解析,解析成ConfigurationClass类添加到ConfigurationClassParser属性configurationClasses中。
parser.parse(candidates);
//验证
parser.validate();
// 获取ConfigurationClassParser中的ConfigurationClass对象集合。
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 去除已经解析的Bean对象。
configClasses.removeAll(alreadyParsed);

// 读取模型并根据其上下文创建bean定义
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 使用 ConfigurationClassBeanDefinitionReader reader 从 configClasses 中加载Bean定义并加载到容器中。
this.reader.loadBeanDefinitions(configClasses);
//处理完的添加到已处理类中。
alreadyParsed.addAll(configClasses);

// 清空候选配置类集合,为下一轮do循环做初始化准备
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// 经过一轮do循环,现在容器中Bean定义数量超过了该次循环开始时的容器内Bean定义数量,
// 说明在该次循环中发现并注册了更多的Bean定义到容器中去,这些新注册的Bean定义
// 也有可能是候选配置类,它们也要被处理用来发现和注册Bean定义
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty()); //循环到没有配置类为止。

// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}

if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}

ConfigurationClassParserparse方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//根据不同的类型来进行解析。
if (bd instanceof AnnotatedBeanDefinition) {
//bd是AnnotateBeanDefinition
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
//bd是AbstractBeanDefinition,并且指定 beanClass 属性
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
// 其他情况
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
// 最后处理DeferredImportSelector接口内容。
// DeferredImportSelector继承自ImportSelector接口。
// ImportSelector 被设计成其实和@Import注解的类同样的导入效果,但是实现 ImportSelector的类可以条件性地决定导入哪些配置。
// DeferredImportSelector的设计目的是在所有其他的配置类被处理后才处理。这也正是该语句被放到本函数最后一行的原因。
this.deferredImportSelectorHandler.process();
}

这里我们看一下第一种情况,其实不管是三个中的任何情况,最后都会调用processConfigurationClass方法来进行处理。

1
2
3
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

processConfigurationClass方法,主要是对解析的ConfigurationClass进行处理,如果已经处理过则合并importBy属性,反之,循环解析配置类并且向上沿着类的接口逐层执行doProcessConfigurationClass方法,直到java提供的类结束循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 首先获取当前ConfigurationClass,检测是否已经被解析了。
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
//如果已经解析了,合并二者的importedBy属性
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 从当前配置类configClass开始向上沿着类继承结构逐层执行doProcessConfigurationClass,
// 直到遇到的父类是由Java提供的类结束循环
// 将类封装成SourceClass类
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
// 设置configurationClasses属性添加当前configuClass对象,用于上一步中的获取当前属性来注册到上下文中。
this.configurationClasses.put(configClass, configClass);
}

doProcessConfigurationClass方法内部实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//如果是@Component注解优先处理内部类/内部成员。
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}

//处理@PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment");
}
}

// 处理@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
//处理@Import注解,这里才是真正的主题。
processImports(configClass, sourceClass, getImports(sourceClass), true);

//处理@ImportResource注解
AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}

//处理Bean@Bean的方法。
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

// Process default methods on interfaces
processInterfaces(configClass, sourceClass);

//如果有父类处理父类。
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}

//如果没有父类则代表处理完成。
return null;
}

来看一下processImports方法,看一下是如何处理@Import注解的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
// 需要处理的SourceClass是否为空,如果为空直接返回。
if (importCandidates.isEmpty()) {
return;
}
//检测循环引用问题。
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
//1.检测是否继承自ImportSelector接口。
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
//创建ImportSelectord对象。
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
//这里判断selector是否是DeferredImportSelector实现。
if (selector instanceof DeferredImportSelector) {
//将调用ConfigurationClassParser内部类DeferredImportSelectorHandler的handle方法,将该类添加到DeferredImportSelectorHandler的属性
//deferredImportSelectors等到后面的最后ConfigurationClassParser类的parse方法的最后执行的方法this.deferredImportSelectorHandler.process()。
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//这里是直接继承ImportSelector接口,并且执行selector的selectImports方法,获取需要解析的类,
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
// 这里会循环解决配置中内容。
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
// 这里是动态注册Bean。
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
//直接处理@Configuration注解的类。
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 从新开始又来处理ConfigurationClass,详细可以看上面的介绍该方法的地方。
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}

整个Spring Boot的运行调用过程如下所示:

1
2
3
4
5
6
7
8
9
10
11
--SpringApplication.run()
----refreshContext(context);
------SpringApplication.refresh(context);
--------ServletWebServerApplicationContext.refresh();
----------AbstractApplicationContext.refresh()
------------invokeBeanFactoryPostProcessors(beanFactory); //这里就会继承自BeanFactoryPostProcessor接口的方法。
--------------PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());//第二个参数传递的就是BeanFactoryPostProcessor的list集合。
----------------invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);//处理BeanDefinitionRegistryPostProcessors,继承自BeanFactoryPostProcessor接口
------------------postProcessor.postProcessBeanDefinitionRegistry(registry);//这里会调用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法来进行处理Bean内容。
--------------------ConfigurationClassPostProcessor.processConfigBeanDefinitions(registry);//解析待处理的Bean。
----------------------ConfigurationClassParser.parse(candidates);//这里就是正式的将待处理的holder解析成ConfigurationClass。

到上面最后一步其实就是已经到了我们上面源码分析的内容位置。

整体流程图大致如下图所示:

处理流程

参考内容

JavaEE开发的颠覆者: Spring Boot实战书籍,其中@Enable*驱动的三种方式摘抄本书

文章目录
  1. 1. Spring Boot自动装配
    1. 1.1. 开篇
    2. 1.2. 引用例子抛出问题
    3. 1.3. @Enable 模块驱动
    4. 1.4. Spring Boot条件注解讲解
    5. 1.5. 自动化配置
    6. 1.6. 参考内容
|
载入天数...载入时分秒...