深入浅析SpringBoot中的自动装配
SpringBoot的自动装配是拆箱即用的基础,也是微服务化的前提。这次主要的议题是,来看看它是怎么样实现的,我们透过源代码来把握自动装配的来龙去脉。
一、自动装配过程分析
1.1、关于@SpringBootApplication
我们在编写SpringBoot项目时,@SpringBootApplication是最常见的注解了,我们可以看一下源代码:
/*
*Copyright2012-2017theoriginalauthororauthors.
*
*LicensedundertheApacheLicense,Version2.0(the"License");
*youmaynotusethisfileexceptincompliancewiththeLicense.
*YoumayobtainacopyoftheLicenseat
*
*http://www.apache.org/licenses/LICENSE-2.0
*
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software
*distributedundertheLicenseisdistributedonan"ASIS"BASIS,
*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
*SeetheLicenseforthespecificlanguagegoverningpermissionsand
*limitationsundertheLicense.
*/
packageorg.springframework.boot.autoconfigure;
importjava.lang.annotation.Documented;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Inherited;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
importorg.springframework.boot.SpringBootConfiguration;
importorg.springframework.boot.context.TypeExcludeFilter;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.ComponentScan;
importorg.springframework.context.annotation.ComponentScan.Filter;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.FilterType;
importorg.springframework.core.annotation.AliasFor;
/**
*Indicatesa{@linkConfigurationconfiguration}classthatdeclaresoneormore
*{@linkBean@Bean}methodsandalsotriggers{@linkEnableAutoConfiguration
*auto-configuration}and{@linkComponentScancomponentscanning}.Thisisaconvenience
*annotationthatisequivalenttodeclaring{@code@Configuration},
*{@code@EnableAutoConfiguration}and{@code@ComponentScan}.
*
*@authorPhillipWebb
*@authorStephaneNicoll
*@since1.2.0
*/
@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@interfaceSpringBootApplication{
/**
*Excludespecificauto-configurationclassessuchthattheywillneverbeapplied.
*@returntheclassestoexclude
*/
@AliasFor(annotation=EnableAutoConfiguration.class,attribute="exclude")
Class>[]exclude()default{};
/**
*Excludespecificauto-configurationclassnamessuchthattheywillneverbe
*applied.
*@returntheclassnamestoexclude
*@since1.3.0
*/
@AliasFor(annotation=EnableAutoConfiguration.class,attribute="excludeName")
String[]excludeName()default{};
/**
*Basepackagestoscanforannotatedcomponents.Use{@link#scanBasePackageClasses}
*foratype-safealternativetoString-basedpackagenames.
*@returnbasepackagestoscan
*@since1.3.0
*/
@AliasFor(annotation=ComponentScan.class,attribute="basePackages")
String[]scanBasePackages()default{};
/**
*Type-safealternativeto{@link#scanBasePackages}forspecifyingthepackagesto
*scanforannotatedcomponents.Thepackageofeachclassspecifiedwillbescanned.
*
*Considercreatingaspecialno-opmarkerclassorinterfaceineachpackagethat
*servesnopurposeotherthanbeingreferencedbythisattribute.
*@returnbasepackagestoscan
*@since1.3.0
*/
@AliasFor(annotation=ComponentScan.class,attribute="basePackageClasses")
Class>[]scanBasePackageClasses()default{};
}
这里面包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan,此处@ComponentScan由于没有指定扫描包,因此它默认扫描的是与该类同级的类或者同级包下的所有类,另外@SpringBootConfiguration,通过源码得知它是一个@Configuration:
/*
*Copyright2012-2016theoriginalauthororauthors.
*
*LicensedundertheApacheLicense,Version2.0(the"License");
*youmaynotusethisfileexceptincompliancewiththeLicense.
*YoumayobtainacopyoftheLicenseat
*
*http://www.apache.org/licenses/LICENSE-2.0
*
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software
*distributedundertheLicenseisdistributedonan"ASIS"BASIS,
*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
*SeetheLicenseforthespecificlanguagegoverningpermissionsand
*limitationsundertheLicense.
*/
packageorg.springframework.boot;
importjava.lang.annotation.Documented;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
importorg.springframework.context.annotation.Configuration;
/**
*IndicatesthataclassprovidesSpringBootapplication
*{@linkConfiguration@Configuration}.CanbeusedasanalternativetotheSpring's
*standard{@code@Configuration}annotationsothatconfigurationcanbefound
*automatically(forexampleintests).
*
*Applicationshouldonlyeverincludeone{@code@SpringBootConfiguration}and
*mostidiomaticSpringBootapplicationswillinherititfrom
*{@code@SpringBootApplication}.
*
*@authorPhillipWebb
*@since1.4.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public@interfaceSpringBootConfiguration{
}
由此我们可以推断出@SpringBootApplication等同于@Configuration@ComponentScan@EnableAutoConfiguration
1.2、@EnableAutoConfiguration
一旦加上此注解,那么将会开启自动装配功能,简单点讲,Spring会试图在你的classpath下找到所有配置的Bean然后进行装配。当然装配Bean时,会根据若干个(Conditional)定制规则来进行初始化。我们看一下它的源码:
/*
*Copyright2012-2017theoriginalauthororauthors.
*
*LicensedundertheApacheLicense,Version2.0(the"License");
*youmaynotusethisfileexceptincompliancewiththeLicense.
*YoumayobtainacopyoftheLicenseat
*
*http://www.apache.org/licenses/LICENSE-2.0
*
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software
*distributedundertheLicenseisdistributedonan"ASIS"BASIS,
*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
*SeetheLicenseforthespecificlanguagegoverningpermissionsand
*limitationsundertheLicense.
*/
packageorg.springframework.boot.autoconfigure;
importjava.lang.annotation.Documented;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Inherited;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
importorg.springframework.boot.autoconfigure.condition.ConditionalOnBean;
importorg.springframework.boot.autoconfigure.condition.ConditionalOnClass;
importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
importorg.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
importorg.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
importorg.springframework.context.annotation.Conditional;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.Import;
importorg.springframework.core.io.support.SpringFactoriesLoader;
/**
*Enableauto-configurationoftheSpringApplicationContext,attemptingtoguessand
*configurebeansthatyouarelikelytoneed.Auto-configurationclassesareusually
*appliedbasedonyourclasspathandwhatbeansyouhavedefined.Forexample,Ifyou
*have{@codetomcat-embedded.jar}onyourclasspathyouarelikelytowanta
*{@linkTomcatEmbeddedServletContainerFactory}(unlessyouhavedefinedyourown
*{@linkEmbeddedServletContainerFactory}bean).
*
*Whenusing{@linkSpringBootApplication},theauto-configurationofthecontextis
*automaticallyenabledandaddingthisannotationhasthereforenoadditionaleffect.
*
*Auto-configurationtriestobeasintelligentaspossibleandwillback-awayasyou
*definemoreofyourownconfiguration.Youcanalwaysmanually{@link#exclude()}any
*configurationthatyouneverwanttoapply(use{@link#excludeName()}ifyoudon't
*haveaccesstothem).Youcanalsoexcludethemviathe
*{@codespring.autoconfigure.exclude}property.Auto-configurationisalwaysapplied
*afteruser-definedbeanshavebeenregistered.
*
*Thepackageoftheclassthatisannotatedwith{@code@EnableAutoConfiguration},
*usuallyvia{@code@SpringBootApplication},hasspecificsignificanceandisoftenused
*asa'default'.Forexample,itwillbeusedwhenscanningfor{@code@Entity}classes.
*Itisgenerallyrecommendedthatyouplace{@code@EnableAutoConfiguration}(ifyou're
*notusing{@code@SpringBootApplication})inarootpackagesothatallsub-packages
*andclassescanbesearched.
*
*Auto-configurationclassesareregularSpring{@linkConfiguration}beans.Theyare
*locatedusingthe{@linkSpringFactoriesLoader}mechanism(keyedagainstthisclass).
*Generallyauto-configurationbeansare{@linkConditional@Conditional}beans(most
*oftenusing{@linkConditionalOnClass@ConditionalOnClass}and
*{@linkConditionalOnMissingBean@ConditionalOnMissingBean}annotations).
*
*@authorPhillipWebb
*@authorStephaneNicoll
*@seeConditionalOnBean
*@seeConditionalOnMissingBean
*@seeConditionalOnClass
*@seeAutoConfigureAfter
*@seeSpringBootApplication
*/
@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{};
}
虽然根据文档注释的说明它指点我们去看EnableAutoConfigurationImportSelector。但是该类在SpringBoot1.5.X版本已经过时了,因此我们看一下它的父类AutoConfigurationImportSelector:
/*
*Copyright2012-2017theoriginalauthororauthors.
*
*LicensedundertheApacheLicense,Version2.0(the"License");
*youmaynotusethisfileexceptincompliancewiththeLicense.
*YoumayobtainacopyoftheLicenseat
*
*http://www.apache.org/licenses/LICENSE-2.0
*
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software
*distributedundertheLicenseisdistributedonan"ASIS"BASIS,
*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
*SeetheLicenseforthespecificlanguagegoverningpermissionsand
*limitationsundertheLicense.
*/
packageorg.springframework.boot.autoconfigure;
importjava.io.IOException;
importjava.util.ArrayList;
importjava.util.Arrays;
importjava.util.Collections;
importjava.util.HashSet;
importjava.util.LinkedHashSet;
importjava.util.List;
importjava.util.Map;
importjava.util.Set;
importjava.util.concurrent.TimeUnit;
importorg.apache.commons.logging.Log;
importorg.apache.commons.logging.LogFactory;
importorg.springframework.beans.BeansException;
importorg.springframework.beans.factory.Aware;
importorg.springframework.beans.factory.BeanClassLoaderAware;
importorg.springframework.beans.factory.BeanFactory;
importorg.springframework.beans.factory.BeanFactoryAware;
importorg.springframework.beans.factory.NoSuchBeanDefinitionException;
importorg.springframework.beans.factory.config.ConfigurableListableBeanFactory;
importorg.springframework.boot.bind.RelaxedPropertyResolver;
importorg.springframework.context.EnvironmentAware;
importorg.springframework.context.ResourceLoaderAware;
importorg.springframework.context.annotation.DeferredImportSelector;
importorg.springframework.core.Ordered;
importorg.springframework.core.annotation.AnnotationAttributes;
importorg.springframework.core.env.ConfigurableEnvironment;
importorg.springframework.core.env.Environment;
importorg.springframework.core.io.ResourceLoader;
importorg.springframework.core.io.support.SpringFactoriesLoader;
importorg.springframework.core.type.AnnotationMetadata;
importorg.springframework.core.type.classreading.CachingMetadataReaderFactory;
importorg.springframework.core.type.classreading.MetadataReaderFactory;
importorg.springframework.util.Assert;
importorg.springframework.util.ClassUtils;
importorg.springframework.util.StringUtils;
/**
*{@linkDeferredImportSelector}tohandle{@linkEnableAutoConfiguration
*auto-configuration}.Thisclasscanalsobesubclassedifacustomvariantof
*{@linkEnableAutoConfiguration@EnableAutoConfiguration}.isneeded.
*
*@authorPhillipWebb
*@authorAndyWilkinson
*@authorStephaneNicoll
*@authorMadhuraBhave
*@since1.3.0
*@seeEnableAutoConfiguration
*/
publicclassAutoConfigurationImportSelector
implementsDeferredImportSelector,BeanClassLoaderAware,ResourceLoaderAware,
BeanFactoryAware,EnvironmentAware,Ordered{
privatestaticfinalString[]NO_IMPORTS={};
privatestaticfinalLoglogger=LogFactory
.getLog(AutoConfigurationImportSelector.class);
privateConfigurableListableBeanFactorybeanFactory;
privateEnvironmentenvironment;
privateClassLoaderbeanClassLoader;
privateResourceLoaderresourceLoader;
@Override
publicString[]selectImports(AnnotationMetadataannotationMetadata){
if(!isEnabled(annotationMetadata)){
returnNO_IMPORTS;
}
try{
AutoConfigurationMetadataautoConfigurationMetadata=AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributesattributes=getAttributes(annotationMetadata);
Listconfigurations=getCandidateConfigurations(annotationMetadata,
attributes);
configurations=removeDuplicates(configurations);
configurations=sort(configurations,autoConfigurationMetadata);
Setexclusions=getExclusions(annotationMetadata,attributes);
checkExcludedClasses(configurations,exclusions);
configurations.removeAll(exclusions);
configurations=filter(configurations,autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations,exclusions);
returnconfigurations.toArray(newString[configurations.size()]);
}
catch(IOExceptionex){
thrownewIllegalStateException(ex);
}
}
protectedbooleanisEnabled(AnnotationMetadatametadata){
returntrue;
}
/**
*Returntheappropriate{@linkAnnotationAttributes}fromthe
*{@linkAnnotationMetadata}.Bydefaultthismethodwillreturnattributesfor
*{@link#getAnnotationClass()}.
*@parammetadatatheannotationmetadata
*@returnannotationattributes
*/
protectedAnnotationAttributesgetAttributes(AnnotationMetadatametadata){
Stringname=getAnnotationClass().getName();
AnnotationAttributesattributes=AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(name,true));
Assert.notNull(attributes,
"Noauto-configurationattributesfound.Is"+metadata.getClassName()
+"annotatedwith"+ClassUtils.getShortName(name)+"?");
returnattributes;
}
/**
*Returnthesourceannotationclassusedbytheselector.
*@returntheannotationclass
*/
protectedClass>getAnnotationClass(){
returnEnableAutoConfiguration.class;
}
/**
*Returntheauto-configurationclassnamesthatshouldbeconsidered.Bydefault
*thismethodwillloadcandidatesusing{@linkSpringFactoriesLoader}with
*{@link#getSpringFactoriesLoaderFactoryClass()}.
*@parammetadatathesourcemetadata
*@paramattributesthe{@link#getAttributes(AnnotationMetadata)annotation
*attributes}
*@returnalistofcandidateconfigurations
*/
protectedListgetCandidateConfigurations(AnnotationMetadatametadata,
AnnotationAttributesattributes){
Listconfigurations=SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
Assert.notEmpty(configurations,
"NoautoconfigurationclassesfoundinMETA-INF/spring.factories.Ifyou"
+"areusingacustompackaging,makesurethatfileiscorrect.");
returnconfigurations;
}
/**
*Returntheclassusedby{@linkSpringFactoriesLoader}toloadconfiguration
*candidates.
*@returnthefactoryclass
*/
protectedClass>getSpringFactoriesLoaderFactoryClass(){
returnEnableAutoConfiguration.class;
}
privatevoidcheckExcludedClasses(Listconfigurations,
Setexclusions){
ListinvalidExcludes=newArrayList(exclusions.size());
for(Stringexclusion:exclusions){
if(ClassUtils.isPresent(exclusion,getClass().getClassLoader())
&&!configurations.contains(exclusion)){
invalidExcludes.add(exclusion);
}
}
if(!invalidExcludes.isEmpty()){
handleInvalidExcludes(invalidExcludes);
}
}
/**
*Handleanyinvalidexcludesthathavebeenspecified.
*@paraminvalidExcludesthelistofinvalidexcludes(willalwayshaveatleastone
*element)
*/
protectedvoidhandleInvalidExcludes(ListinvalidExcludes){
StringBuildermessage=newStringBuilder();
for(Stringexclude:invalidExcludes){
message.append("\t-").append(exclude).append(String.format("%n"));
}
thrownewIllegalStateException(String
.format("Thefollowingclassescouldnotbeexcludedbecausetheyare"
+"notauto-configurationclasses:%n%s",message));
}
/**
*Returnanyexclusionsthatlimitthecandidateconfigurations.
*@parammetadatathesourcemetadata
*@paramattributesthe{@link#getAttributes(AnnotationMetadata)annotation
*attributes}
*@returnexclusionsoranemptyset
*/
protectedSetgetExclusions(AnnotationMetadatametadata,
AnnotationAttributesattributes){
Setexcluded=newLinkedHashSet();
excluded.addAll(asList(attributes,"exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
returnexcluded;
}
privateListgetExcludeAutoConfigurationsProperty(){
if(getEnvironment()instanceofConfigurableEnvironment){
RelaxedPropertyResolverresolver=newRelaxedPropertyResolver(
this.environment,"spring.autoconfigure.");
Mapproperties=resolver.getSubProperties("exclude");
if(properties.isEmpty()){
returnCollections.emptyList();
}
Listexcludes=newArrayList();
for(Map.Entryentry:properties.entrySet()){
Stringname=entry.getKey();
Objectvalue=entry.getValue();
if(name.isEmpty()||name.startsWith("[")&&value!=null){
excludes.addAll(newHashSet(Arrays.asList(StringUtils
.tokenizeToStringArray(String.valueOf(value),","))));
}
}
returnexcludes;
}
RelaxedPropertyResolverresolver=newRelaxedPropertyResolver(getEnvironment(),
"spring.autoconfigure.");
String[]exclude=resolver.getProperty("exclude",String[].class);
return(Arrays.asList(exclude==null?newString[0]:exclude));
}
privateListsort(Listconfigurations,
AutoConfigurationMetadataautoConfigurationMetadata)throwsIOException{
configurations=newAutoConfigurationSorter(getMetadataReaderFactory(),
autoConfigurationMetadata).getInPriorityOrder(configurations);
returnconfigurations;
}
privateListfilter(Listconfigurations,
AutoConfigurationMetadataautoConfigurationMetadata){
longstartTime=System.nanoTime();
String[]candidates=configurations.toArray(newString[configurations.size()]);
boolean[]skip=newboolean[candidates.length];
booleanskipped=false;
for(AutoConfigurationImportFilterfilter:getAutoConfigurationImportFilters()){
invokeAwareMethods(filter);
boolean[]match=filter.match(candidates,autoConfigurationMetadata);
for(inti=0;iresult=newArrayList(candidates.length);
for(inti=0;i(result);
}
protectedListgetAutoConfigurationImportFilters(){
returnSpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
this.beanClassLoader);
}
privateMetadataReaderFactorygetMetadataReaderFactory(){
try{
returngetBeanFactory().getBean(
SharedMetadataReaderFactoryContextInitializer.BEAN_NAME,
MetadataReaderFactory.class);
}
catch(NoSuchBeanDefinitionExceptionex){
returnnewCachingMetadataReaderFactory(this.resourceLoader);
}
}
protectedfinalListremoveDuplicates(Listlist){
returnnewArrayList(newLinkedHashSet(list));
}
protectedfinalListasList(AnnotationAttributesattributes,Stringname){
String[]value=attributes.getStringArray(name);
returnArrays.asList(value==null?newString[0]:value);
}
privatevoidfireAutoConfigurationImportEvents(Listconfigurations,
Setexclusions){
Listlisteners=getAutoConfigurationImportListeners();
if(!listeners.isEmpty()){
AutoConfigurationImportEventevent=newAutoConfigurationImportEvent(this,
configurations,exclusions);
for(AutoConfigurationImportListenerlistener:listeners){
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
protectedListgetAutoConfigurationImportListeners(){
returnSpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class,
this.beanClassLoader);
}
privatevoidinvokeAwareMethods(Objectinstance){
if(instanceinstanceofAware){
if(instanceinstanceofBeanClassLoaderAware){
((BeanClassLoaderAware)instance)
.setBeanClassLoader(this.beanClassLoader);
}
if(instanceinstanceofBeanFactoryAware){
((BeanFactoryAware)instance).setBeanFactory(this.beanFactory);
}
if(instanceinstanceofEnvironmentAware){
((EnvironmentAware)instance).setEnvironment(this.environment);
}
if(instanceinstanceofResourceLoaderAware){
((ResourceLoaderAware)instance).setResourceLoader(this.resourceLoader);
}
}
}
@Override
publicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{
Assert.isInstanceOf(ConfigurableListableBeanFactory.class,beanFactory);
this.beanFactory=(ConfigurableListableBeanFactory)beanFactory;
}
protectedfinalConfigurableListableBeanFactorygetBeanFactory(){
returnthis.beanFactory;
}
@Override
publicvoidsetBeanClassLoader(ClassLoaderclassLoader){
this.beanClassLoader=classLoader;
}
protectedClassLoadergetBeanClassLoader(){
returnthis.beanClassLoader;
}
@Override
publicvoidsetEnvironment(Environmentenvironment){
this.environment=environment;
}
protectedfinalEnvironmentgetEnvironment(){
returnthis.environment;
}
@Override
publicvoidsetResourceLoader(ResourceLoaderresourceLoader){
this.resourceLoader=resourceLoader;
}
protectedfinalResourceLoadergetResourceLoader(){
returnthis.resourceLoader;
}
@Override
publicintgetOrder(){
returnOrdered.LOWEST_PRECEDENCE-1;
}
}
首先该类实现了DeferredImportSelector接口,这个接口继承了ImportSelector:
/*
*Copyright2002-2013theoriginalauthororauthors.
*
*LicensedundertheApacheLicense,Version2.0(the"License");
*youmaynotusethisfileexceptincompliancewiththeLicense.
*YoumayobtainacopyoftheLicenseat
*
*http://www.apache.org/licenses/LICENSE-2.0
*
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software
*distributedundertheLicenseisdistributedonan"ASIS"BASIS,
*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
*SeetheLicenseforthespecificlanguagegoverningpermissionsand
*limitationsundertheLicense.
*/
packageorg.springframework.context.annotation;
importorg.springframework.core.type.AnnotationMetadata;
/**
*Interfacetobeimplementedbytypesthatdeterminewhich@{@linkConfiguration}
*class(es)shouldbeimportedbasedonagivenselectioncriteria,usuallyoneormore
*annotationattributes.
*
*An{@linkImportSelector}mayimplementanyofthefollowing
*{@linkorg.springframework.beans.factory.AwareAware}interfaces,andtheirrespective
*methodswillbecalledpriorto{@link#selectImports}:
*
-
*
- {@linkorg.springframework.context.EnvironmentAwareEnvironmentAware} *
- {@linkorg.springframework.beans.factory.BeanFactoryAwareBeanFactoryAware} *
- {@linkorg.springframework.beans.factory.BeanClassLoaderAwareBeanClassLoaderAware} *
- {@linkorg.springframework.context.ResourceLoaderAwareResourceLoaderAware} *
ImportSelectorsareusuallyprocessedinthesamewayasregular{@code@Import} *annotations,however,itisalsopossibletodeferselectionofimportsuntilall *{@code@Configuration}classeshavebeenprocessed(see{@linkDeferredImportSelector} *fordetails). * *@authorChrisBeams *@since3.1 *@seeDeferredImportSelector *@seeImport *@seeImportBeanDefinitionRegistrar *@seeConfiguration */ publicinterfaceImportSelector{ /** *Selectandreturnthenamesofwhichclass(es)shouldbeimportedbasedon *the{@linkAnnotationMetadata}oftheimporting@{@linkConfiguration}class. */ String[]selectImports(AnnotationMetadataimportingClassMetadata); }
该接口主要是为了导入@Configuration的配置项,而DeferredImportSelector是延期导入,当所有的@Configuration都处理过后才会执行。
回过头来我们看一下AutoConfigurationImportSelector的selectImport方法:
@Override
publicString[]selectImports(AnnotationMetadataannotationMetadata){
if(!isEnabled(annotationMetadata)){
returnNO_IMPORTS;
}
try{
AutoConfigurationMetadataautoConfigurationMetadata=AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributesattributes=getAttributes(annotationMetadata);
Listconfigurations=getCandidateConfigurations(annotationMetadata,
attributes);
configurations=removeDuplicates(configurations);
configurations=sort(configurations,autoConfigurationMetadata);
Setexclusions=getExclusions(annotationMetadata,attributes);
checkExcludedClasses(configurations,exclusions);
configurations.removeAll(exclusions);
configurations=filter(configurations,autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations,exclusions);
returnconfigurations.toArray(newString[configurations.size()]);
}
catch(IOExceptionex){
thrownewIllegalStateException(ex);
}
}
该方法刚开始会先判断是否进行自动装配,而后会从META-INF/spring-autoconfigure-metadata.properties读取元数据与元数据的相关属性,紧接着会调用getCandidateConfigurations方法:
/**
*Returntheauto-configurationclassnamesthatshouldbeconsidered.Bydefault
*thismethodwillloadcandidatesusing{@linkSpringFactoriesLoader}with
*{@link#getSpringFactoriesLoaderFactoryClass()}.
*@parammetadatathesourcemetadata
*@paramattributesthe{@link#getAttributes(AnnotationMetadata)annotation
*attributes}
*@returnalistofcandidateconfigurations
*/
protectedListgetCandidateConfigurations(AnnotationMetadatametadata,
AnnotationAttributesattributes){
Listconfigurations=SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
Assert.notEmpty(configurations,
"NoautoconfigurationclassesfoundinMETA-INF/spring.factories.Ifyou"
+"areusingacustompackaging,makesurethatfileiscorrect.");
returnconfigurations;
}
/**
*Returntheclassusedby{@linkSpringFactoriesLoader}toloadconfiguration
*candidates.
*@returnthefactoryclass
*/
protectedClass>getSpringFactoriesLoaderFactoryClass(){
returnEnableAutoConfiguration.class;
}
在这里又遇到我们的老熟人了--SpringFactoryiesLoader,它会读取META-INF/spring.factories下的EnableAutoConfiguration的配置,紧接着在进行排除与过滤,进而得到需要装配的类。最后让所有配置在META-INF/spring.factories下的AutoConfigurationImportListener执行AutoConfigurationImportEvent事件,代码如下:
privatevoidfireAutoConfigurationImportEvents(Listconfigurations, Set exclusions){ List listeners=getAutoConfigurationImportListeners(); if(!listeners.isEmpty()){ AutoConfigurationImportEventevent=newAutoConfigurationImportEvent(this, configurations,exclusions); for(AutoConfigurationImportListenerlistener:listeners){ invokeAwareMethods(listener); listener.onAutoConfigurationImportEvent(event); } } } protectedList getAutoConfigurationImportListeners(){ returnSpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader); }
二、何时进行自动装配
在前面的环节里只是最终要确定哪些类需要被装配,在SpringBoot时何时处理这些自动装配的类呢?下面我们简要的分析一下:
2.1、AbstractApplicationContext的refresh方法:
这个方法老生常谈了其中请大家关注一下这个方法:
//Invokefactoryprocessorsregisteredasbeansinthecontext. invokeBeanFactoryPostProcessors(beanFactory);
在这里是处理BeanFactoryPostProcessor的,那么我们在来看一下这个接口BeanDefinitionRegistryPostProcessor:
/*
*Copyright2002-2010theoriginalauthororauthors.
*
*LicensedundertheApacheLicense,Version2.0(the"License");
*youmaynotusethisfileexceptincompliancewiththeLicense.
*YoumayobtainacopyoftheLicenseat
*
*http://www.apache.org/licenses/LICENSE-2.0
*
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software
*distributedundertheLicenseisdistributedonan"ASIS"BASIS,
*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
*SeetheLicenseforthespecificlanguagegoverningpermissionsand
*limitationsundertheLicense.
*/
packageorg.springframework.beans.factory.support;
importorg.springframework.beans.BeansException;
importorg.springframework.beans.factory.config.BeanFactoryPostProcessor;
/**
*Extensiontothestandard{@linkBeanFactoryPostProcessor}SPI,allowingfor
*theregistrationoffurtherbeandefinitionsbeforeregular
*BeanFactoryPostProcessordetectionkicksin.Inparticular,
*BeanDefinitionRegistryPostProcessormayregisterfurtherbeandefinitions
*whichinturndefineBeanFactoryPostProcessorinstances.
*
*@authorJuergenHoeller
*@since3.0.1
*@seeorg.springframework.context.annotation.ConfigurationClassPostProcessor
*/
publicinterfaceBeanDefinitionRegistryPostProcessorextendsBeanFactoryPostProcessor{
/**
*Modifytheapplicationcontext'sinternalbeandefinitionregistryafterits
*standardinitialization.Allregularbeandefinitionswillhavebeenloaded,
*butnobeanswillhavebeeninstantiatedyet.Thisallowsforaddingfurther
*beandefinitionsbeforethenextpost-processingphasekicksin.
*@paramregistrythebeandefinitionregistryusedbytheapplicationcontext
*@throwsorg.springframework.beans.BeansExceptionincaseoferrors
*/
voidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry)throwsBeansException;
}
该接口继承了BeanFactoryPostProcessor。
2.2、ConfigurationClassPostProcessor类
该类主要处理@Configuration注解的,它实现了BeanDefinitionRegistryPostProcessor, 那么也间接实现了BeanFactoryPostProcessor,关键代码如下:
@Override
publicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory){
intfactoryId=System.identityHashCode(beanFactory);
if(this.factoriesPostProcessed.contains(factoryId)){
thrownewIllegalStateException(
"postProcessBeanFactoryalreadycalledonthispost-processoragainst"+beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if(!this.registriesPostProcessed.contains(factoryId)){
//BeanDefinitionRegistryPostProcessorhookapparentlynotsupported...
//SimplycallprocessConfigurationClasseslazilyatthispointthen.
processConfigBeanDefinitions((BeanDefinitionRegistry)beanFactory);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(newImportAwareBeanPostProcessor(beanFactory));
}
/**
*Buildandvalidateaconfigurationmodelbasedontheregistryof
*{@linkConfiguration}classes.
*/
publicvoidprocessConfigBeanDefinitions(BeanDefinitionRegistryregistry){
//.....省略部分代码
//Parseeach@Configurationclass
ConfigurationClassParserparser=newConfigurationClassParser(
this.metadataReaderFactory,this.problemReporter,this.environment,
this.resourceLoader,this.componentScanBeanNameGenerator,registry);
Setcandidates=newLinkedHashSet(configCandidates);
SetalreadyParsed=newHashSet(configCandidates.size());
do{
parser.parse(candidates);
parser.validate();
SetconfigClasses=newLinkedHashSet(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
//Readthemodelandcreatebeandefinitionsbasedonitscontent
if(this.reader==null){
this.reader=newConfigurationClassBeanDefinitionReader(
registry,this.sourceExtractor,this.resourceLoader,this.environment,
this.importBeanNameGenerator,parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if(registry.getBeanDefinitionCount()>candidateNames.length){
String[]newCandidateNames=registry.getBeanDefinitionNames();
SetoldCandidateNames=newHashSet(Arrays.asList(candidateNames));
SetalreadyParsedClasses=newHashSet();
for(ConfigurationClassconfigurationClass:alreadyParsed){
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for(StringcandidateName:newCandidateNames){
if(!oldCandidateNames.contains(candidateName)){
BeanDefinitionbd=registry.getBeanDefinition(candidateName);
if(ConfigurationClassUtils.checkConfigurationClassCandidate(bd,this.metadataReaderFactory)&&
!alreadyParsedClasses.contains(bd.getBeanClassName())){
candidates.add(newBeanDefinitionHolder(bd,candidateName));
}
}
}
candidateNames=newCandidateNames;
}
}
while(!candidates.isEmpty());
//....省略部分代码
}
其实这里注释已经很清楚了,我们可以清楚的看到解析每一个@ConfigurationClass的关键类是:ConfigurationClassParser,那么我们继续看一看这个类的parse方法:
publicvoidparse(SetconfigCandidates){ this.deferredImportSelectors=newLinkedList (); for(BeanDefinitionHolderholder:configCandidates){ BeanDefinitionbd=holder.getBeanDefinition(); try{ if(bdinstanceofAnnotatedBeanDefinition){ parse(((AnnotatedBeanDefinition)bd).getMetadata(),holder.getBeanName()); } elseif(bdinstanceofAbstractBeanDefinition&&((AbstractBeanDefinition)bd).hasBeanClass()){ parse(((AbstractBeanDefinition)bd).getBeanClass(),holder.getBeanName()); } else{ parse(bd.getBeanClassName(),holder.getBeanName()); } } catch(BeanDefinitionStoreExceptionex){ throwex; } catch(Throwableex){ thrownewBeanDefinitionStoreException( "Failedtoparseconfigurationclass["+bd.getBeanClassName()+"]",ex); } } processDeferredImportSelectors(); }
在这里大家留意一下最后一句processDeferredImportSelectors方法,在这里将会对DeferredImportSelector进行处理,这样我们就和AutoConfigurationSelectImporter结合到一起了:
privatevoidprocessDeferredImportSelectors(){
ListdeferredImports=this.deferredImportSelectors;
this.deferredImportSelectors=null;
Collections.sort(deferredImports,DEFERRED_IMPORT_COMPARATOR);
for(DeferredImportSelectorHolderdeferredImport:deferredImports){
ConfigurationClassconfigClass=deferredImport.getConfigurationClass();
try{
String[]imports=deferredImport.getImportSelector().selectImports(configClass.getMetadata());
processImports(configClass,asSourceClass(configClass),asSourceClasses(imports),false);
}
catch(BeanDefinitionStoreExceptionex){
throwex;
}
catch(Throwableex){
thrownewBeanDefinitionStoreException(
"Failedtoprocessimportcandidatesforconfigurationclass["+
configClass.getMetadata().getClassName()+"]",ex);
}
}
}
请大家关注这句代码:String[]imports=deferredImport.getImportSelector().selectImports(configClass.getMetadata());在这里deferredImport的类型为DeferredImportSelectorHolder:
privatestaticclassDeferredImportSelectorHolder{
privatefinalConfigurationClassconfigurationClass;
privatefinalDeferredImportSelectorimportSelector;
publicDeferredImportSelectorHolder(ConfigurationClassconfigClass,DeferredImportSelectorselector){
this.configurationClass=configClass;
this.importSelector=selector;
}
publicConfigurationClassgetConfigurationClass(){
returnthis.configurationClass;
}
publicDeferredImportSelectorgetImportSelector(){
returnthis.importSelector;
}
}
在这个内部类里持有了一个DeferredImportSelector的引用,至此将会执行自动装配的所有操作
三、总结
1)自动装配还是利用了SpringFactoriesLoader来加载META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它会经过exclude和filter等操作,最终确定要装配的类
2) 处理@Configuration的核心还是ConfigurationClassPostProcessor,这个类实现了BeanFactoryPostProcessor,因此当AbstractApplicationContext执行refresh方法里的invokeBeanFactoryPostProcessors(beanFactory)方法时会执行自动装配
以上所述是小编给大家介绍的SpringBoot中的自动装配,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!