@SpringBootApplication注解
下面是该注解重要代码:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { xxxxxxxxxxxxx } |
看名字就能多少了解这些注解的功能,这里重点关注下@EnableAutoConfiguration注解;
@EnableAutoConfiguration注解
下面是该注解重要代码:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {}; } |
这里关注下AutoConfigurationImportSelector类;
AutoConfigurationImportSelector类
下面是该注解重要代码:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { XXXXXXX } |
Order接口:里面只有一个getOrder方法,不重要;
EnvironmentAware接口:里面只有一个setEnvironment方法,不重要;
BeanFactoryAware接口:里面只有一个setBeanFactory方法,不重要;
ResourceLoaderAware接口:里面只有一个setResourceLoader方法,不重要;
BeanClassLoaderAware接口:里面只有一个setBeanClassLoader方法,不重要;
DeferredImportSelector接口:里面有个selectImports方法,这里重点关注下:
下面是AutoConfigurationImportSelector.selectImports方法源码:
public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } } |
该selectImports方法需要返回一个String[]数组,我们接下来看一下这个String[]里面放的是什么内容,这里我们查看getAutoConfigurationEntry方法的源代码:
getAutoConfigurationEntry方法源码:
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry (AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { AnnotationAttributes attributes = this.getAttributes(annotationMetadata); List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); 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); } } |
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
这里也就是通过getCandidateConfigurations方法返回一个List<String>,然后再经过filter过滤等操作,最终形成结果,因此,我们这里继续看一下最原始的数据集合List<String>:
下面是getCandidateConfigurations方法源码:
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; } |
也就是说,这里读取的是META-INF/spring.factories文件,来形成的List<String>的原始数据,我们根据IDEA的提示,发现该类位于spring-boot-autoconfigure-2.2.2.RELEASE.jar/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector/getCandidateConfigurations,
然后再根据Maven/conf/settings.xml中配置的<localRepository/>路径,去寻找spring-boot-autoconfigure-2.2.2.RELEASE.jar,然后通过ZIP发现了META-INF/spring.factories文件,解压jar得到spring.factories文件,下面是该文件的源码:
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnBeanCondition,\ org.springframework.boot.autoconfigure.condition.OnClassCondition,\ org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
# 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,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\ org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\ org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\ org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\ org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\ org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\ org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\ org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\ org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\ org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\ org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\ org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\ org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\ org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\ org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\ org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\ org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\ org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\ org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\ org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\ org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\ org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\ org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
# Failure analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\ org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\ org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer
# Template availability providers org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider |
这里既然得知,初始化属性的文件来自于spring.factories文件,那Spring Boot是用哪个JAVA类接受这些配置呢?
我们继续查看this.getSpringFactoriesLoaderFactoryClass()方法,下面是该方法的源代码:
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; } |
也就是说,这里通过EnableAutoConfiguration来封装的属性值,这里借用HttpEncodingAutoConfiguration类来说明AutoConfiguration类的作用;
HttpEncodingAutoConfiguration类
下面是HttpEncodingAutoConfiguration类的重要代码:
@Configuration( proxyBeanMethods = false ) @EnableConfigurationProperties({HttpProperties.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({CharacterEncodingFilter.class}) @ConditionalOnProperty( prefix = "spring.http.encoding", value = {"enabled"}, matchIfMissing = true ) public class HttpEncodingAutoConfiguration |
@EnableConfigurationProperties({HttpProperties.class}):说明其属性,都要填充到HttpProperties类中,这里可以查看该类的源代码来了解具体的属性信息;
@ConditionalOnProperty注解:意思是spring.http.encoding.enabled=true来启动该类;
public HttpEncodingAutoConfiguration(HttpProperties properties) { this.properties = properties.getEncoding(); } |
该类只有一个构造方法,还是有参的构造方法;
下面是HttpProperties重要源码:
@ConfigurationProperties( prefix = "spring.http" ) public class HttpProperties |
总结1:Spring Boot自动配置
通过@SpringBootApplication注解,来加载spring-boot-autoconfigure.jar/META-INF/spring.factories,来加载Spring Boot默认的框架级别的配置,考虑到上一个章节学习到了properties加载的顺序与优先级,因此,我们可以通过自定义properties来覆盖spring.factories中同名的参数;
总结2:Spring Boot某个组件的自动配置
以HttpEncodingAutoConfiguration为例,
第1步:把“spring.http”为前缀的属性,全部加载到HttpProperties类中;
第2步:容器在初始化HttpEncodingAutoConfiguration时,则把HttpProperties作为构造参数,传递给构造方法;
第3步:使用HttpEncodingAutoConfiguration提供的功能;
综上所述,其他类似的Spring Boot的模块,都会对应着一个XXXAutoConfiguration,来负责加载properties文件、提供功能;
总结3:开发时注意事项
①看看自己需要哪个组件,再去看看Spring Boot是否提供了对应的组件;
②如果Spring Boot提供了我们想要的组件,然后参考下官方说明文档,看看需要覆盖哪些属性;
扩展1:官方链接地址
下面是官方的连接,直接查看官方说明文档即可,总比查看XXXProperties类要方便多了:https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/html/index.html
上面提到的HttpEncodingAutoConfiguration就是对应的Web properties
扩展2-@Conditional注解扩展
Spring Boot对@Conditional注解进行了多次扩展,下面列举出几个比较常用的扩展以及含义:
@Conditional扩展注解 | 作用 |
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中是否存在指定Bean |
@ConditionalOnMissingBean | 容器中是否不存在指定Bean |
@ConditionalOnExpression | 是否满足SpEL表达式 |
@ConditionalOnClass | 系统中有否有指定的类 |
@ConditionalOnMissingClass | 系统中是否没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是否是web环境 |
@ConditionalOnNotWebApplication | 当前是否不是web环境 |
@ConditionalOnJndi | 是否存在jndi指定项 |
这里以HttpEncodingAutoConfiguration源码为案例来讲解,下面是该类的源码:
@Configuration( proxyBeanMethods = false ) @EnableConfigurationProperties({HttpProperties.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({CharacterEncodingFilter.class}) @ConditionalOnProperty( prefix = "spring.http.encoding", value = {"enabled"}, matchIfMissing = true ) public class HttpEncodingAutoConfiguration |
这里,以@ConditionalOnProperty为例来说明,那我们紧接着查看该注解的源码:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented @Conditional({OnPropertyCondition.class}) public @interface ConditionalOnProperty { String[] value() default {};
String prefix() default "";
String[] name() default {};
String havingValue() default "";
boolean matchIfMissing() default false; } |
然后,再紧接着查看OnPropertyCondition类,OnPropertyCondition类继承了SpringBootCondition类,SpringBootCondition类实现了Condition接口;
下面是SpringBootCondition类关键源码:
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { String classOrMethodName = getClassOrMethodName(metadata);
try { ConditionOutcome outcome = this.getMatchOutcome(context, metadata); this.logOutcome(classOrMethodName, outcome); this.recordEvaluation(context, classOrMethodName, outcome); return outcome.isMatch(); } catch (NoClassDefFoundError var5) { throw new IllegalStateException("Could not evaluate condition on " + classOrMethodName + " due to " + var5.getMessage() + " not found. Make sure your own configuration does not rely on that class. This can also happen if you are @ComponentScanning a springframework package (e.g. if you put a @ComponentScan in the default package by mistake)", var5); } catch (RuntimeException var6) { throw new IllegalStateException("Error processing condition on " + this.getName(metadata), var6); } }
public abstract ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata); |
这里我们可以知道,起到核心作用的是ConditionOutcome outcome = this.getMatchOutcome(context, metadata);而getMatchOutcome方法是一个抽象方法,最后还是由OnPropertyCondition类来实现该抽象方法;
下面是OnPropertyCondition.getMatchOutcome方法源码:
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { List<AnnotationAttributes> allAnnotationAttributes = this.annotationAttributesFromMultiValueMap(metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName())); List<ConditionMessage> noMatch = new ArrayList(); List<ConditionMessage> match = new ArrayList(); Iterator var6 = allAnnotationAttributes.iterator();
while(var6.hasNext()) { AnnotationAttributes annotationAttributes = (AnnotationAttributes)var6.next(); ConditionOutcome outcome = this.determineOutcome(annotationAttributes, context.getEnvironment()); (outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage()); }
if (!noMatch.isEmpty()) { return ConditionOutcome.noMatch(ConditionMessage.of(noMatch)); } else { return ConditionOutcome.match(ConditionMessage.of(match)); } } |
这里重点看一下determineOutcome方法的collectProperties方法,下面是collectProperties方法源码:
private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) { String[] var4 = this.names; int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) { String name = var4[var6]; String key = this.prefix + name; if (resolver.containsProperty(key)) { if (!this.isMatch(resolver.getProperty(key), this.havingValue)) { nonMatching.add(name); } } else if (!this.matchIfMissing) { missing.add(name); } }
} |
这里的this.name指的是@ConditionalOnProperty注解的name数组,这里的name是{"enabled"},然后for循环遍历name数组,把prefix和name进行拼接,这里的prefix就是注解里的"spring.http.encoding.",name就是"enabled",拼接后就是"spring.http.encoding.enabled",因此就是判断该属性值是什么,然后一层层回调到最上层,下面是部分重要源码:
Spec(AnnotationAttributes annotationAttributes) { |
private String[] getNames(Map<String, Object> annotationAttributes) { |
private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) { String[] var4 = this.names; int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) { String name = var4[var6]; String key = this.prefix + name; if (resolver.containsProperty(key)) { if (!this.isMatch(resolver.getProperty(key), this.havingValue)) { nonMatching.add(name); } } else if (!this.matchIfMissing) { missing.add(name); } }
} |
private boolean isMatch(String value, String requiredValue) { |
综上所述,XXXAutoConfiguration类必须在一定的条件下才能生效,我们可以在application.properties/yml中启用debug=true来让控制台打印自动配置报告,进而得知哪些自动配置类生效,报告里Negative matches表示哪些自动配置类没有启用,Positive matches表示哪些自动配置类启用