基础7-深入了解Spring Boot的自动配置

@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

然后跳转到下面链接地址:https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/html/appendix-application-properties.html#server-properties

上面提到的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) {
    String prefix = annotationAttributes.getString("prefix").trim();
    if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) {
        prefix = prefix + ".";
    }

    this.prefix = prefix;
    this.havingValue = annotationAttributes.getString("havingValue");
    this.names = this.getNames(annotationAttributes);
    this.matchIfMissing = annotationAttributes.getBoolean("matchIfMissing");
}

 

private String[] getNames(Map<String, Object> annotationAttributes) {
    String[] value = (String[])((String[])annotationAttributes.get("value"));
    String[] name = (String[])((String[])annotationAttributes.get("name"));
    Assert.state(value.length > 0 || name.length > 0, "The name or value attribute of @ConditionalOnProperty must be specified");
    Assert.state(value.length == 0 || name.length == 0, "The name and value attributes of @ConditionalOnProperty are exclusive");
    return value.length > 0 ? value : name;
}

 

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) {
    if (StringUtils.hasLength(requiredValue)) {
        return requiredValue.equalsIgnoreCase(value);
    } else {
        return !"false".equalsIgnoreCase(value);
    }
}

综上所述,XXXAutoConfiguration类必须在一定的条件下才能生效,我们可以在application.properties/yml中启用debug=true来让控制台打印自动配置报告,进而得知哪些自动配置类生效,报告里Negative matches表示哪些自动配置类没有启用,Positive matches表示哪些自动配置类启用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值