1、SpringBoot的主配置类
@SpringBootApplication
public class SpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplication.class, args);
}
}
可以看到,@SpringBootApplication包含了三个注解@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
-
@SpringBootConfiguration表示Spring的配置类
-
@ComponentScan扫描符合规则的类并将其注入到Spring容器。其扫描路径可配置,默认是扫描被此注解修饰的类的包及其子包,所以SpringBoot的启动类一般都放在最高级包路径下。
-
@EnableAutoConfiguration自动配置关键注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = {org.springframework.boot.context.TypeExcludeFilter.class}), @Filter(type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class})})
public @interface SpringBootApplication {
}
2、@EnableAutoConfiguration
- @EnableAutoConfiguration包含
@Import({AutoConfigurationImportSelector.class})
,这个就是自动配置的重中之重。此类配合Import有批量注册bean的功能。
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
}
//ImportSelector实现类,此类配合Import有批量注册bean的功能
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
public String[] selectImports( AnnotationMetadata annotationMetadata ) {
if ( !isEnabled( annotationMetadata ) )
{
return(NO_IMPORTS);
}
/*步骤一:读取 /META-INF/spring-autoconfigure-metadata.properties文件,
先筛选一下要加载哪些配置类,再把符合条件配置类的信息封装到AutoConfigurationMetadata*/
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata( this.beanClassLoader );
/*步骤二:读取 META-INF/spring.factories文件,把其信息封装到
AutoConfigurationEntry里,再将步骤一获取的配置类与此处获取的配置类
执行过滤、去重、排序等操作,保存满足条件的配置类*/
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry( autoConfigurationMetadata, annotationMetadata );
/*返回满足自动配置条件的类的字符串数组,后交给@Import注解,将其注入到Spring容器中,
至此,完成SpringBoot的自动配置!*/
return(StringUtils.toStringArray( autoConfigurationEntry.getConfigurations() ) );
}
}
- 点击进入getAutoConfigurationEntry方法,再进入getCandidateConfigurations方法就可以发现读取了包路径下META-INF/spring.factories里面配置的*AutoConfiguration自动配置类
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//这里getCandidateConfigurations就是返回自动配置spring.factories配置项信息。
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//set去重
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
//getCandidateConfigurations读取spring.factories文件
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
spring-boot-autoconfigure包下META-INF/spring.factories,截取一部分。然后springboot就会帮我们把这些自动配置类条件性注册到ioc容器中。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
- 通过@import注解读取并注册META-INF/spring.factories里的配置类*AutoConfiguration。
以RedisAutoConfiguration配置类为例:
@Configuration
说明这是一个config配置类;@ConditionalOnClass
表示某个class位于类路径上,才会实例化一个Bean;@EnableConfigurationProperties
使@ConfigurationProperties生效并被Configuration类的对应属性注入,这样就实现了我们自定义application.yml配置参数设置。@ConditionalOnMissingBean
仅在当前上下文中不存在某个对象时,才会实例化一个Bean
@Configuration
@ConditionalOnClass({org.springframework.data.redis.core.RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class,JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = {"redisTemplate"})
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
//RedisProperties数据源类,对应application.yml配置
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private int database = 0;
private String url;
private String host = "localhost";
private String password;
private int port = 379;
private boolean ssl;
private Duration timeout;
private Sentinel sentinel;
private Cluster cluster;
}
总结
-
@SpringBootApplication等同于三个注解:
@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
-
springboot启动时@EnableAutoConfiguration会扫描所有jar路径下META-INF/spring.factories,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能
-
每一个配置类装载的过程依赖于Properties的自定义属性,通过@Condition派生注解实现是否注入对应bean实现自动配置