Spring Boot自动装配原理源码分析

Spring Boot自动装配原理源码分析

1.环境准备

使用IDEA Spring Initializr快速创建一个Spring Boot项目

添加一个Controller类

@RestController
public class HelloController { @RequestMapping(“hello”)

public String hello() {<br/>
    return &#34;hello&#34;;<br/>
}<br/>

}

主配置类如下

@SpringBootApplication
public class SpringbootQuickstartApplication { public static void main(String[] args) {

    SpringApplication.run(SpringbootQuickstartApplication.class, args);<br/>
}

}

2.注解分析

@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {

@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),<br/>
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)<br/>

})
public @interface SpringBootApplication {

@SpringBootApplication
@Configuration
public @interface SpringBootConfiguration {
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

3.自动装配的主角

@EnableAutoConfiguration@AutoConfigurationPackage@Import

(1)、@AutoConfigurationPackage

点进该注解

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}

在点进Register,这是一个静态内部类

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

  register(registry, new PackageImport(metadata).getPackageName());<br/>

} @Override
public Set&lt;Object&gt; determineImports(AnnotationMetadata metadata) {

 return Collections.singleton(new PackageImport(metadata));<br/>

} }

new PackageImport(metadata).getPackageName()

再看一眼metadata,果然,就是主配置类

因此,这个注解的作用就是将主配置类所在的包作为自动配置包进行管理

(2)、@Import(AutoConfigurationImportSelector.class)

@Import
selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {

  return NO_IMPORTS;<br/>

}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader

     .loadMetadata(this.beanClassLoader);<br/>

AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,

     annotationMetadata);<br/>

return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,

  AnnotationMetadata annotationMetadata) {<br/>

if (!isEnabled(annotationMetadata)) {

  return EMPTY_ENTRY;<br/>

}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List&lt;String&gt; configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set&lt;String&gt; exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

getCandidateConfigurationsxxxAtuoConfiguration

那么这些自动配置类是如何获取的呢,从哪里获取的呢?

getCandidateConfigurations
protected List&lt;String&gt; getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

List&lt;String&gt; configurations =<br/>
    SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),<br/>
     getBeanClassLoader());<br/>

Assert.notEmpty(configurations, “… …”);
return configurations;
}

loadFactoryNamesFACTORIES_RESOURCE_LOCATIONMETA-INF/spring.factories
public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”;
public static List&lt;String&gt; loadFactoryNames(Class&lt;?&gt; factoryType, @Nullable ClassLoader classLoader) {

	String factoryTypeName = factoryType.getName();<br/>
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());<br/>
}
private static Map&lt;String, List&lt;String&gt;&gt; loadSpringFactories(@Nullable ClassLoader classLoader) {<br/>
	MultiValueMap&lt;String, String&gt; result = cache.get(classLoader);<br/>
	if (result != null) {<br/>
		return result;<br/>
	}<br/>
	try {<br/>
		Enumeration&lt;URL&gt; urls = (classLoader != null ?<br/>
				classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :<br/>
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));<br/>
		result = new LinkedMultiValueMap&lt;&gt;();<br/>
		while (urls.hasMoreElements()) {<br/>
			URL url = urls.nextElement();<br/>
			UrlResource resource = new UrlResource(url);<br/>
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);<br/>
			for (Map.Entry&lt;?, ?&gt; entry : properties.entrySet()) {<br/>
				String factoryTypeName = ((String) entry.getKey()).trim();<br/>
				for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {<br/>
					result.add(factoryTypeName, factoryImplementationName.trim());<br/>
				}<br/>
			}<br/>
		}<br/>
		cache.put(classLoader, result);<br/>
		return result;<br/>
	}<br/>
	catch (IOException ex) {<br/>
		throw new IllegalArgumentException(&#34;Unable to load factories from location [&#34; +<br/>
				FACTORIES_RESOURCE_LOCATION + &#34;]&#34;, ex);<br/>
	}<br/>
}<br/>

spring-boot-autoconfigure-2.2.4.RELEASE.jar/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=<br/> org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,<br/> org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,<br/> org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,<br/> org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,<br/> org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,<br/> org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,<br/> org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,<br/> org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,<br/> org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,<br/> org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,<br/> org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,<br/> org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,<br/> org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,<br/> org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,<br/> org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration
… …

4.类的加载时机

ConditionalOnClass@ConditionaOn xxx

WebMvcAutoConfiguration