Spring Boot 自动配置的实现
SpringBoot自动配置
来看下springboot中自动配置的注解
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public@interfaceEnableAutoConfiguration{
StringENABLED_OVERRIDE_PROPERTY="spring.boot.enableautoconfiguration";
/**
*Excludespecificauto-configurationclassessuchthattheywillneverbeapplied.
*@returntheclassestoexclude
*/
Class>[]exclude()default{};
/**
*Excludespecificauto-configurationclassnamessuchthattheywillneverbe
*applied.
*@returntheclassnamestoexclude
*@since1.3.0
*/
String[]excludeName()default{};
}
- exclude()可以排除一些自动配置的内容
- excludeName通过名称排除自动配置内容
再来看下,@EnableAutoConfiguration是怎么处理自动配置的呢?
注意到@Import(EnableAutoConfigurationImportSelector.class)
publicclassEnableAutoConfigurationImportSelector
extendsAutoConfigurationImportSelector{
@Override
protectedbooleanisEnabled(AnnotationMetadatametadata){
if(getClass().equals(EnableAutoConfigurationImportSelector.class)){
returngetEnvironment().getProperty(
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY,Boolean.class,
true);
}
returntrue;
}
}
}
再来看下AutoConfigurationImportSelector,主要是接口的ImportSelector的实现
@Override
publicString[]selectImports(AnnotationMetadataannotationMetadata){
if(!isEnabled(annotationMetadata)){
returnNO_IMPORTS;
}
try{
//1、自动配置的元数据spring-autocomfigure-metadata.properties
//自动配置的开启条件
AutoConfigurationMetadataautoConfigurationMetadata=AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributesattributes=getAttributes(annotationMetadata);
//获取设置的自动配置列表spring.factories
Listconfigurations=getCandidateConfigurations(annotationMetadata,
attributes);
configurations=removeDuplicates(configurations);
configurations=sort(configurations,autoConfigurationMetadata);
//获取要排除的自动配置列表,可以通过注解@EnableAutoConfiguration的exclude和
//配置文件设置spring.autoconfigure.excludekey的值
Setexclusions=getExclusions(annotationMetadata,attributes);
checkExcludedClasses(configurations,exclusions);
configurations.removeAll(exclusions);
//通过spring-autocomfigure-metadata.propertiesConditionOnClass条件进行过滤
configurations=filter(configurations,autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations,exclusions);
returnconfigurations.toArray(newString[configurations.size()]);
}
catch(IOExceptionex){
thrownewIllegalStateException(ex);
}
}
看下spring.factories文件
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.CloudAutoConfiguration,\ 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.CassandraRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ 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.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ 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.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.freemarker.FreeMarkerAutoConfiguration,\ org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\ org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
再看下springframework中ConfigurationClassParser的处理方式,会解析@Import里的接口ImportSelector返回的所有配置类,那是怎么配置的呢,如JpaRepositoriesAutoConfiguration
@Configuration
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean({JpaRepositoryFactoryBean.class,
JpaRepositoryConfigExtension.class})
@ConditionalOnProperty(prefix="spring.data.jpa.repositories",name="enabled",havingValue="true",matchIfMissing=true)
@Import(JpaRepositoriesAutoConfigureRegistrar.class)
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
publicclassJpaRepositoriesAutoConfiguration{
}
从上面可以看到,有很多的@ConditionalOn**的注解,我们来看下ConditionEvaluator这个条件计算器,会去计算出当前这个配置类是否要开启,而这些@ConditionalOn**是依赖于@Conditional这个注解,如 @ConditionalOnBean最终是通过Condition接口来作条件选择
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public@interfaceConditionalOnBean{
/**
*Theclasstypeofbeanthatshouldbechecked.Theconditionmatcheswhenanyof
*theclassesspecifiediscontainedinthe{@linkApplicationContext}.
*@returntheclasstypesofbeanstocheck
*/
Class>[]value()default{};
/**
*Theclasstypenamesofbeanthatshouldbechecked.Theconditionmatcheswhenany
*oftheclassesspecifiediscontainedinthe{@linkApplicationContext}.
*@returntheclasstypenamesofbeanstocheck
*/
String[]type()default{};
/**
*Theannotationtypedecoratingabeanthatshouldbechecked.Theconditionmatches
*whenanyoftheannotationsspecifiedisdefinedonabeaninthe
*{@linkApplicationContext}.
*@returntheclass-levelannotationtypestocheck
*/
Class[]annotation()default{};
/**
*Thenamesofbeanstocheck.Theconditionmatcheswhenanyofthebeannames
*specifiediscontainedinthe{@linkApplicationContext}.
*@returnthenameofbeanstocheck
*/
String[]name()default{};
/**
*Strategytodecideiftheapplicationcontexthierarchy(parentcontexts)shouldbe
*considered.
*@returnthesearchstrategy
*/
SearchStrategysearch()defaultSearchStrategy.ALL;
}
Springboot的autoconfigure是囊括了所有可以和spring整合的项目,但大部分情况下,并不是所以的项目都会启用,通过Condition和@Conditional来判断条件
- 判断classPath是否存在指定的类 @ConditionalOnClass
- 判断ApplicationContext中是否存在指定的Bean @ConditionalOnBean
- 配置环境中是否存在特定的配置项 @ConditionalOnProperty
- 配置环境中指定的配置项是否存在指定的值
禁用配置
当前也是可以禁用某些我们不想要的默认配置,如上面加载时说到,会排除一些配置(exclude)
- 设置@EnableAutoConfiguration的exclude配置
- 在配置文件增加spring.autoconfigure.exclude配置
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。