SpringBoot의 자동 어셈블리는 Unboxing의 기초이며 마이크로 서비스의 전제 조건입니다. 이번에는 주요 주제는 그것이 어떻게 구현되는지 확인하는 것입니다. 우리는 소스 코드를 사용하여 자동 어셈블리의 내부를 파악합니다.
1.1. @SpringBootApplication 소개
SpringBoot 프로젝트를 작성할 때 @SpringBootApplication이 가장 일반적인 주석입니다. 소스 코드를 살펴볼 수 있습니다.
/ * * 저작권 2012-2017 원래 저자 또는 저자. * * Apache 라이센스에 따라 라이센스가 부여 된 버전 2.0 ( "라이센스"); * 라이센스를 준수하는 것 외에는이 파일을 사용할 수 없습니다. * 귀하는 * * http://www.apache.org/license/license/license-2.0 *에서 라이센스 사본을 얻을 수 있습니다. 적용 가능한 법률에 의해 요구되거나 서면으로 동의하지 않는 한, 라이센스에 따라 배포 된 소프트웨어 *는 "기준"에 배포됩니다. * 특정 언어 거버넌스 권한 및 라이센스에 따른 제한에 대한 라이센스를 참조하십시오. */패키지 org.springframework.boot.autoconfigure; import java.lang.annotation.documented; import java.lang.elementtype; import java.lang.annotation.inherited; import java.lang.annotation.restention; import java.lang.annotation.retentionpolicy; java.lang.annotation.target; import org.springframework.springbootconfiguration; import org.sprameframework.context.context.typeexcludefilter; import org.springframework.context.annotation.bean; import org.springcan.context.annottext.annottext.annottext org.springframework.context.annotation.componentscan.filter; import org.spramframework.context.annotation.configuration; import org.sprameframework.context.annotation.filtertype; import org.springframework.core.annotation.alias 구성} 하나 이상의 * {@link bean @bean} 메소드를 선언하고 {@link enableautoconfiguration * auto-configuration} 및 {@link componentscan component scanning}을 트리거하는 configuration} 클래스. 이것은 {@code @configuration}, * {@code @enableautoconfiguration} 및 {@code @componentscan}을 선언하는 것과 동등한 편의 * 주석입니다. * * @Author Phillip Webb * @Author Stephane Nicoll * @since 1.2.0 */@target (eleMpertype.type) @retention (resentpolicy.runtime)@documented@inherited@springbootconfiguration@componentscan (EnableAutoconFiguration@componentscan = @filter = {filterpepe. typeexcludefilter.class), @filter (type = filtertype.custom, classes = autoconfigurationexcludefilter.class)}) public @interface springbootApplication { /*** 적용되지 않는 특정 자동 구성 클래스를 제외합니다. * @ @return */ @Aliasfor (annotation = enableAutoConfiguration.class, attribute = "exclude") class <?> [] exclude () default {}; /** * 적용되지 않도록 특정 자동 구성 클래스 이름을 제외합니다. * @클래스 이름을 제외 할 클래스 이름 * @since 1.3.0 */ @Aliasfor (annotation = enableAutoConfiguration.class, attribute = "excludEname") string [] excludEname () default {}; /*** 주석이 달린 구성 요소를 스캔 할 기본 패키지. 문자열 기반 패키지 이름에 대한 유형-안전 대안은 {@link #scanbasepackageclasses} *를 사용하십시오. * @return base 패키지 스캔 * @since 1.3.0 */ @Aliasfor (annotation = componentsCan.class, attribute = "basePackages") String [] scanbasepackages () default {}; /** * 주석이 달린 구성 요소를 스캔 할 패키지를 지정하려면 {@link #scanbasepackages}에 대한 대안 유형 대안. 지정된 각 클래스의 패키지가 스캔됩니다. * <p> * 각 패키지에서 특수 NO-OP 마커 클래스 또는 인터페이스를 작성 하여이 속성에서 참조하는 것 외에는 다른 목적을 제공하지 않습니다. * @return base 패키지 스캔 * @since 1.3.0 */ @Aliasfor (Annotation = componentsCan.class, attribute = "BasePackAgeClasses") class <?> [] scanbasepackageclasses () 기본값 {};}여기에는 @springbootconfiguration, @enableautoconfiguration, @componentscan이 포함됩니다. 여기서는 스캐닝 패키지가 지정되지 않았으므로 기본적으로 클래스와 동일한 레벨 또는 동일한 레벨 패키지로 모든 클래스를 스캔합니다. 또한 @SpringBootConfiguration에서는 소스 코드를 통해 @Configuration이라는 것을 알 수 있습니다.
/ * * 저작권 2012-2016 원래 저자 또는 저자. * * Apache 라이센스에 따라 라이센스가 부여 된 버전 2.0 ( "라이센스"); * 라이센스를 준수하는 것 외에는이 파일을 사용할 수 없습니다. * 귀하는 * * http://www.apache.org/license/license/license-2.0 *에서 라이센스 사본을 얻을 수 있습니다. 적용 가능한 법률에 의해 요구되거나 서면으로 동의하지 않는 한, 라이센스에 따라 배포 된 소프트웨어 *는 "기준"에 배포됩니다. * 특정 언어 거버넌스 권한 및 라이센스에 따른 제한에 대한 라이센스를 참조하십시오. */패키지 org.springframework.boot; import java.lang.annotation.documented; import java.lang.annotation.elementtype; import java.lang.annotation.retention; import java.lang.annotation.restentation.restionation.rang.annotation.targage; import; org.springframework.context.annotation.configuration;/** * 클래스가 스프링 부팅 응용 프로그램 * {@link configuration @configuration}을 제공 함을 나타냅니다. 스프링 * 표준 {@code @configuration} 주석에 대한 대안으로 사용할 수 있으므로 구성을 자동으로 찾을 수 있도록 (예 : 테스트에서) 구성을 찾을 수 있습니다. * <p> * 응용 프로그램은 <em> one </em> {@code @springbootconfiguration}을 포함해야하며 * 대부분의 관용 스프링 부팅 응용 프로그램은 * {@code @springbootApplication}에서 상속됩니다. * * @Author Phillip Webb * @since 1.4.0 */@target (elementtype.type) @retention (retentionpolicy.runtime)@documented@configurationpublic @intersface springbootconfiguration {}이것으로부터 우리는 @springbootapplication이 @configuration @componentscan @enableautoconfiguration과 동일하다고 추론 할 수 있습니다.
1.2. @enableautoconfiguration
이 주석이 추가되면 자동 조립 기능이 활성화됩니다. 간단히 말해서, Spring은 ClassPath에서 구성된 모든 Bean을 찾은 다음 조립합니다. 물론 콩을 조립할 때는 여러 (조건부) 사용자 정의 규칙에 따라 초기화됩니다. 소스 코드를 살펴 보겠습니다.
/ * * 저작권 2012-2017 원래 저자 또는 저자. * * Apache 라이센스에 따라 라이센스가 부여 된 버전 2.0 ( "라이센스"); * 라이센스를 준수하는 것 외에는이 파일을 사용할 수 없습니다. * 귀하는 * * http://www.apache.org/license/license/license-2.0 *에서 라이센스 사본을 얻을 수 있습니다. 적용 가능한 법률에 의해 요구되거나 서면으로 동의하지 않는 한, 라이센스에 따라 배포 된 소프트웨어 *는 "기준"에 배포됩니다. * 특정 언어 거버넌스 권한 및 라이센스에 따른 제한에 대한 라이센스를 참조하십시오. */패키지 org.springframework.boot.autoconfigure; import java.lang.annotation.documented; import java.lang.elementtype; import java.lang.annotation.inherited; import java.lang.annotation.restention; import java.lang.annotation.retentionpolicy; java.lang.annotation.target; import org.springframework.boot.autoconfigure.condition.conditionalonbean; import org.spramframework.boot.autoconfigure.condition.conditionalonbean; import org.springframewort.autoconfigureconfigurecon.conditonmition org.springframework.boot.context.embedded.embeddedservletcontainerfactory; import org.springframework.boot.context.embedded.tomcat.tomcatembeddedservletcontainer lemportory; import org.springframework.context.annotational.conditional; import; org.springframework.context.annotation.configuration; import org.springframework.context.annotation.import; import org.springframework.core.io.support.springfactoryloader;/** * 봄 애플리케이션 컨텍스트의 자동 구성 가능성을 활성화 할 수 있습니다. 자동 구성 클래스는 일반적으로 클래스 경로와 정의 한 콩을 기준으로 적용됩니다. 예를 들어, ClassPath에 {@code tomcat-embedded.jar}가 있으면 * {@link tomcatembeddedservletcontainerfactory} (자신의 * {@link embeddedServletcontainerCactory} bean을 정의하지 않는 한)을 원할 것입니다. * <p> * {@Link SpringBootApplication}을 사용할 때 컨텍스트의 자동 구성이 자동으로 활성화 되므로이 주석을 추가하면 추가 효과가 없습니다. * <p> * 자동 구성은 가능한 한 지능적이며 자신의 구성을 더 많이 정의 할 때 되돌아 갈 것입니다. 적용하고 싶지 않은 * 구성 ({@link #excludename ()}를 사용하지 않는 경우 {@link #exclude ()} 항상 수동으로 {@link #exclude ()}를 수동으로 수 있습니다. * {@code spring.autoconfigure.exclude} 속성을 통해 제외 할 수도 있습니다. 사용자 정의 콩이 등록 된 후 자동 구성이 항상 적용됩니다. * <p> * 일반적으로 {@code @enableautoconfiguration}으로 주석이 달린 클래스 패키지는 일반적으로 {@code @springbootapplication}을 통해 특정한 의미를 가지며 종종 '기본값'으로 사용됩니다. 예를 들어 {@code @entity} 클래스를 스캔 할 때 사용됩니다. * 일반적으로 {@code @enableautoconfiguration}을 배치하는 것이 좋습니다 ( * {@code @springbootapplication}을 사용하지 않는 경우}를 루트 패키지에 사용하여 모든 하위 포장지 * 및 클래스를 검색 할 수 있습니다. * <p> * 자동 구성 클래스는 일반 스프링 {@link configuration} bean입니다. 이들은 {@link springfactorioryloader} 메커니즘 (이 클래스에 비해 키)을 사용하여 위치합니다. * 일반적으로 자동 구성 Bean은 {@link 컨디셔닝 @Conditional} Beans입니다 (대부분 *는 {@link 컨디셔너 클래스 @conditionalOnclass} 및 * {@link 컨디셔닝 비안 @ConditionalOnMissingBean} annotations를 사용합니다. * * @Author Phillip Webb * @Author Stephane Nicoll * @SEEE 컨디셔너 컨디션 * @See 컨디셔닝 컨디션 비안 * @Seee QuiconalOnclass * @autoconfiguR 이후 * @see springbootApplication */@suppresswarnings ( "Deprecation")@target (elementtype.type) @retention (rendentionpolicy.runtime)@hod "스프링 .boot.enableautoconfiguration"; /*** 적용되지 않도록 특정 자동 구성 클래스를 제외하십시오. * @return */ class <?> [] exclude () default {}; /** * 적용되지 않도록 특정 자동 구성 클래스 이름을 제외합니다. * @클래스 이름을 제외하여 * @since 1.3.0 */ string [] excludename () default {};}문서 주석에 따르면 enableautoconfigurationimportselector를 보도록 안내합니다. 그러나 클래스는 SpringBoot1.5.x 버전으로 구식이므로 부모 클래스 AutoconFigurationImportSelector를 살펴 보겠습니다.
/ * * 저작권 2012-2017 원래 저자 또는 저자. * * Apache 라이센스에 따라 라이센스가 부여 된 버전 2.0 ( "라이센스"); * 라이센스를 준수하는 것 외에는이 파일을 사용할 수 없습니다. * 귀하는 * * http://www.apache.org/license/license/license-2.0 *에서 라이센스 사본을 얻을 수 있습니다. 적용 가능한 법률에 의해 요구되거나 서면으로 동의하지 않는 한, 라이센스에 따라 배포 된 소프트웨어 *는 "기준"에 배포됩니다. * 라이센스에 따른 특정 언어 통치 권한 및 * 제한 사항에 대한 라이센스를 참조하십시오. */패키지 org.springframework.boot.autoconfigure; import java.io.ioexception; import java.util.arraylist; import java.util.arrays; import java.util.collections; import java.util.hashset; import java.util.linkedhashset; import java.util. import; java.util.map; import java.util.set; import java.util.concurrent.timeUnit; import org.apache.commons.logging.log; import org.apache.commons.logging.logovey; import org.springframework.beans.beansection; import org.spram.spram.spramework.spramework.spramework org.springframework.beans.bean.bean.beanclassloaderaware; import org.springframework.beans.bean.beanfactory; import org.springframework.beans.bean.beanfactoryaware; import org.spramework.beans.beans.beans.beans.bean.nosuchbeandefinitection; import org.springframework.beans.beans.config.configurablelistablebeanfactory; import org.springframework.bind.bind.bind.rightorg.springframework.context.envondermentaware; import org.springframework.restourestourestouresceleater awnexter restour excelout org.springframework.context.annotation.deferredimportselector; import org.springframework.core.ordered; import org.spramframework.core.annotation.annotationattributes; import org.spramework.core.env.configurableenvironmentment; org.springframework.core.env.environment; import org.springframework.core.io.resourceloader; import org.springframework.core.io.support.springfactoryloader; import org.spramework.core.annotationmetadata; 수입 org.springframework.core.type.classreading.cachingmetadataReaderFactory; import org.springframework.core.type.classreading.metadateReaderFactory; import org.spramframework.util.assert; import org.springframework.util.classutils; org.springframework.util.stringutils;/** * {@link inableautoconfiguration * auto-configuration}을 처리하려면}. 이 클래스는 * {@link enableautoconfiguration @enableautoconfiguration}의 사용자 정의 변형이 서브 클래스를 할 수 있습니다. 필요합니다. * * @Author Phillip Webb * @Author Andy Wilkinson * @Author Stephane Nicoll * @Author Madhura Bhave * @since 1.3.0 * @see enableAutoconfiguration */public class autoconfigurationimportselector emperredimportselector, privice weperateware, resourceloware, reneraware, formerawore, resourceloware. 정적 최종 문자열 [] no_imports = {}; 개인 정적 최종 로그 로거 = logfactory .getLog (autoconfigurationImportSelector.class); 개인 구성 블리리스트 가능한 BeanFactory; 개인 환경 환경; 개인 클래스 로더 BeanClassLoader; Private ResourceLoader Resourceloader; @override public String [] selectImports (AnnotationMetadata AnnotationMetadata) {if (! isenabled (anotationmetadata)) {return no_imports; } try {autoconfigurationMetadata autoconfigurationMetadata = autoconfigurationMetAdataloader .loadmetadata (this.beanclassloader); AnnotationAttributes 속성 = getAttributes (AnnotationMetadata); list <string> configurations = getCandidAteConfigUrations (AnnotationMetadata, Attributes); 구성 = removeduplicates (구성); configurations = sort (configurations, autoconfigurationMetadata); set <string> 제외 = getExclusions (AnnotationMetadata, Attributes); CheckexCludedClasses (구성, 제외); configurations.removeall (제외); 구성 = 필터 (구성, AutoConfigurationMetadata); fireautoconfigurationimportevents (구성, 제외); return configurations.toArray (new String [configurations.size ()]; } catch (ioException ex) {Throw New ImperalStateException (EX); }} Protected Boolean isenabled (Annotationmetadata Metadata) {return true; } /** * * {@link annotationmetadata}에서 적절한 {@link annotationattributes}를 반환합니다. 기본적 으로이 메소드는 * {@link #getannotationClass ()}에 대한 속성을 반환합니다. * @param 메타 데이터 주석 메타 데이터 * @return Annotation 속성 */ Protected AnnotationAttributes getAttributes (annotationmetadata metadata) {String name = getAnnotationClass (). getName (); AnnotationAttributes attributes = AnnotationAttributes .frommap (metadata.getannotationattributes (name, true)); assert.notnull (속성, "자가 구성 속성이 없음"은 " + metadata.getCrassName () +" " + classUtils.getShortName (name) +"? 반환 속성; } /*** 선택기가 사용하는 소스 주석 클래스를 반환합니다. * @ @주석 클래스 */ Protected Class <?> getAnnotationClass () {return enableAutoconfiguration.class; } /*** 고려해야 할 자동 구성 클래스 이름을 반환합니다. 기본적으로 *이 메소드는 * {@link #getSpringsCringFactoriorDerFactoryClass ()}과 함께 {@Link SpringFactoryLoader}를 사용하여 후보를로드합니다. * @param metadata 소스 메타 데이터 * @param 속성 {@link #getattributes (annotationmetadata) 주석 * attributes} * @return 후보 구성 목록 */ 보호 목록 <string> getCandidateConfigurations (AnnotationationmetataTATA, annotationAttibutes) itcandidateConfigUrations (getCandidAtataTATATATATATATIATS) ILSTIBUTES). SpringFactorioryLoader.loadFactoryNames (getSpringFactorioryLoaderFactoryClass (), getBeanClassLoader ()); Assert.notempty (구성, "meta-inf/spring.factories에서 찾은 자동 구성 클래스가 없습니다." + "가 사용자 정의 포장을 사용하는 경우 파일이 올바른지 확인하십시오."); 반환 구성; } /** * {@link springfactorioryloader}에서 사용한 클래스를 구성하여 구성 * 후보를로드합니다. * @공장 클래스 */ Protected Class <?> getSpringFactorioryLoaderFactoryClass () {return enableAutoConfiguration.class; } private void checkexcludedClasses (list <string> 구성, set <string> exclus) {list <string> invalidexcludes = new arraylist <string> (exclusions.size ()); for (string exclus : exclus) {if (classutils.ispresent (제외, getClass (). getClassLoader ()) &&! configurations.contains (제외)) {invalidexcludes.add (제외); }} if (! invalidexCludes.isempty ()) {handleInValidexCludes (invalidexCludes); }} /*** 지정된 유효하지 않은 제외를 처리합니다. * @param invalidexcluds invalid의 목록은 제외 (항상 하나 이상의 * 요소를 가질 것입니다) */ protected void handlidexcludes (list <string> invalidexcludes) {stringbuilder message = new StringBuilder (); for (string Exclude : invalidexCludes) {message.append ( "/t-") .append (제외) .append (string.format ( "%n")); } 새 불법 상태를 던지십시오. String .format ( "다음 클래스는 자동 구성 클래스가 아님" + "이기 때문에 제외 할 수 없습니다 :%n%s", 메시지); } /*** 후보 구성을 제한하는 제외를 반환합니다. * @param metadata 소스 메타 데이터 * @param 속성 {@link #getattributes (annotationmetadata) 주석 * attributes} * @return xclusions 또는 빈 세트 */ 보호 세트 <string> getExclusions (AnnotationmetAdata, annotationAttributes attributes) {string> excluded> excluded> excluded>. 제외 .addall (Aslist (속성, "제외")); 제외 .addall (arrays.aslist (attributes.getStringArray ( "excludeName"))); 제외 .addall (getExCludeAutoConfigUrationSproperty ()); 반품 제외; } private list <string> getExcludeAutoConfigUrationSproperty () {if (getEnvironment () 구성 가능한 경우, configurableEnvironment의 인스턴스) {allingedPropertyresolver Resolver = New RelaxEdPropertyresolver (this.environment, "spring.autoconfigure" map <string, object> properties = resolver.getSubProperties ( "제외"); if (properties.isempty ()) {return collections.emptylist (); } list <string> 제외 = new ArrayList <string> (); for (map.Entry <string, object> entry : properties.entryset ()) {String name = enlice.getKey (); 객체 값 = Entry.GetValue (); if (name.isempty () || name.startSwith ( "[") && value! = null) {excludes.addall (new Hashset <string> (arrays.aslist (StringUtils .TokenizetOstringArray (string.Valuef (value), "))); }} return excludes; } allingPropertyresolver Resolver = New RestayPropertyresolver (GetEnvironment (), "Spring.AutoConfigure"); 문자열 [] exclude = resolver.getProperty ( "제외", String []. class); return (arrays.aslist (제외 == null? new String [0] : Exclude)); } private list <string> sort (list <string> 구성, AutoConfigurationMetadata AutoConfigurationMetadata)는 ioException {configurations = new AutoConFigUrationSter (getMetAdatAreaderAttory (), AutoConFigurationMetAdata (autoconFigurationMetAdata). 반환 구성; } private list <string> 필터 (list <string> 구성, AutoConfigurationMetadata AutoConfigurationMetadata) {long starttime = system.nanoTime (); 문자열 [] 후보자 = configurations.toArray (new String [configurations.size ()]); 부울 [] skip = new boolean [후보자 .length]; 부울 건너 뛰기 = 거짓; for (autoconfigurationImportFilter 필터 : getAutoConfigurationImportFilters ()) {invokeawaremethods (필터); 부울 [] match = filter.match (후보자, AutoConfigurationMetadata); for (int i = 0; i <match.length; i ++) {if (! match [i]) {skip [i] = true; 건너 뛰기 = 참으로; }}}} if (! smipped) {return configurations; } list <string> result = new ArrayList <string> (후보자 .length); for (int i = 0; i <후보. }} if (logger.istraceEnabled ()) {int numberFiltered = configurations.size () - result.size (); logger.trace ( "필터링 된" + 숫자 필터링 + "자동 구성 클래스" + timeUnit.nanoseconds.tomillis (System.NanoTime () -StartTime) + "MS"); } return new arrayList <string> (결과); } 보호 목록 <AutoConfigurationImportFilter> getAutoConfigurationImportFilters () {return springfactoriordoader.loadfactories (autoconfigurationImportfilter.class, this.BeanClassLoader); } private metAdatAreaderFactory getMetAdatAreaderFactory () {try {return getBeanFactory (). getBean (sharedMetAdAreAderFactoryContexTinitializer.bean_name, metadatAreaderFactory.class); } catch (nosuchbeandefinitionException ex) {새로운 캐싱 메타 타이어드 레터 플로어 (this.resourceloader); }} Protected Final <T> List <T> removedUplicates (List <T> List) {return New ArrayList <T> (New LinkedHashset <T> (List)); } 보호 된 최종 목록 <string> aslist (AnnotationAttributes 속성, 문자열 이름) {string [] value = attributes.getStringArray (이름); return arrays.aslist (value == null? new String [0] : value); } private void fireautoconfigurationImportevents (list <string> 구성, set <string> xcclusions) {list <autoconfigurationImportListener> 리스너 = getAutoConfigurationImportListeners (); if (! warners.isempty ()) {autoconfigurationImportevent event = new AutoconFigurationImportEvent (이, 구성, excclusions); for (autoconfigurationImportListener 리스너 : 리스너) {invokeawaremethods (리스너); LEARTER.ONAUTOCONFIGURINGIMPORTEVENT (이벤트); }}} 보호 목록 <AutoConfigurationImportListener> getAutoConfigurationImportListeners () {return springfactoriordoLoader.loadFactories (autoconfigurationImportListener.class, this.BeanClassLoader); } private void invokeawaremethods (객체 인스턴스) {if (instance instanceof aware) {if (beanclassloaderaware의 인스턴스 인스턴스 인스턴스 인스턴스 인스턴스) {((beanclassloaderaware) 인스턴스). } if (beanfactoryaware의 인스턴스 인스턴스) {((beanfactoryaware) instance. } if (instance -ofnistentaware) {((환경) 인스턴스) .setenvironment (this.environment); } if (resourceloaderaware의 인스턴스 인스턴스) {(((resourceloaderaware) instance) .setResourceloader (this.ResourcelOader); }}} @override public void setbeanfactory (beanfactory beanfactory)는 beansexception {assert.isinstanceof (configurablelistablebeanfactory.class, beanfactory); this.beanfactory = (configurableBleistableBeanFactory) beanfactory; . } @override public void setbeanclassloader (classloader classloader) {this.beanclassloader = classloader; } 보호 된 클래스 로더 GetBeanClassLoader () {return this.BeanClassLoader; } @override public void setenvironment (환경 환경) {this.environment = 환경; } 보호 된 최종 환경 getEnvironment () {return this.environment; } @override public void setresourceloader (resourceloader resourceloader) {this.resourceloader = resourceloader; } 보호 된 최종 리소스 셀러 로더 getResourceloader () {return this.resourceloader; } @override public int getOrder () {return ordered.lowest_precedence -1; }}먼저,이 클래스는 importselector를 물려받는 DeferredimportSelector 인터페이스를 구현합니다.
/ * * 저작권 2002-2013 원래 저자 또는 저자. * * Apache 라이센스에 따라 라이센스가 부여 된 버전 2.0 ( "라이센스"); * 라이센스를 준수하는 것 외에는이 파일을 사용할 수 없습니다. * 귀하는 * * http://www.apache.org/license/license/license-2.0 *에서 라이센스 사본을 얻을 수 있습니다. 적용 가능한 법률에 의해 요구되거나 서면으로 동의하지 않는 한, 라이센스에 따라 배포 된 소프트웨어 *는 "기준"에 배포됩니다. * 라이센스에 따른 특정 언어 통치 권한 및 * 제한 사항에 대한 라이센스를 참조하십시오. */패키지 org.springframework.context.annotation; import org.springframework.core.type.annotationmetadata;/** * 인터페이스 @{ @link configuration} * class (es)를 결정하는 유형에 따라 구현할 수있는 인터페이스, 일반적으로 하나 또는 더 많은 * 주석 특성을 결정해야합니다. * * <p> {@link importselector}는 다음 중 하나를 구현할 수 있습니다 * {@link org.spramework.beans.beans.factory.aware aware} 인터페이스, 해당 * 메소드는 {@link #selectimports} : * <ul> * <li> {@link org.springframwork.contex.contex.contex. EnvironmentAware} </li> * <li> {@link org.springframework.beans.beans.beans.beanfactoryaware beanfactoryaware} </li> * <li> {@link org.springframework.beans.beans.beanclassloaderaware beanclassloaderaware} </li> * <le link. org.springframework.context.resourceloaderaware resourceloaderaware} </li> * </ul> * <p> importselectors는 일반적으로 정기적 인 {@code @import} * 주석과 같은 방식으로 처리됩니다. 자세한 내용은 deferredimportSelector} *. * * @Author Chris Beams * @since 3.1 * @see deferredimportSelector * @see import * @see importBeanDefinitionRregistrar * @see configuration * /public interface importSelector { /** * 클래스 (es)의 이름을 선택하고 {@link annotation}} @link annotationmetata}를 기준으로 가져와야합니다. */ string [] selectImports (AnnotationMetadata importingClassMetadata);}이 인터페이스는 주로 @configuration의 구성 항목을 가져 오는 데 사용되며 DeferredimportSelector는 이연 된 가져 오기이며 모든 @configurations가 처리 된 후에 만 실행됩니다.
AutoConfigurationImportSelector의 SELECTIMPORT 메소드를 살펴 보겠습니다.
@override public String [] selectImports (AnnotationMetadata AnnotationMetadata) {if (! isenabled (anotationmetadata)) {return no_imports; } try {autoconfigurationMetadata autoconfigurationMetadata = autoconfigurationMetAdataloader .loadmetadata (this.beanclassloader); AnnotationAttributes 속성 = getAttributes (AnnotationMetadata); list <string> configurations = getCandidAteConfigUrations (AnnotationMetadata, Attributes); 구성 = removeduplicates (구성); configurations = sort (configurations, autoconfigurationMetadata); <string> excclusions = getExclusions (AnnotationMetadata, Attributes); CheckexCludedClasses (구성, 제외); configurations.removeall (제외); 구성 = 필터 (구성, AutoConfigurationMetadata); FireautoconfigurationImportevents (구성, Excclusions); return configurations.toArray (new String [configurations.size ()]; } catch (ioException ex) {Throw New ImperalStateException (EX); }}
처음 에이 방법은 먼저 자동 어셈블리를 수행할지 여부를 결정한 다음 Meta-Inf/Spring-Autoconfigure-Metadata.properties에서 메타 데이터 및 메타 데이터의 관련 특성을 읽은 다음 getCandidateConfigurations 메소드를 호출합니다.
/*** 고려해야 할 자동 구성 클래스 이름을 반환합니다. 기본적으로 *이 메소드는 * {@link #getSpringsCringFactoriorDerFactoryClass ()}과 함께 {@Link SpringFactoryLoader}를 사용하여 후보를로드합니다. * @param metadata 소스 메타 데이터 * @param 속성 {@link #getattributes (annotationmetadata) 주석 * attributes} * @return 후보 구성 목록 */ 보호 목록 <string> getCandidateConfigurations (AnnotationationmetataTATA, annotationAttibutes) itcandidateConfigUrations (getCandidAtataTATATATATATATIATS) ILSTIBUTES). SpringFactorioryLoader.loadFactoryNames (getSpringFactorioryLoaderFactoryClass (), getBeanClassLoader ()); Assert.notempty (구성, "meta-inf/spring.factories에서 찾은 자동 구성 클래스가 없습니다." + "가 사용자 정의 포장을 사용하는 경우 파일이 올바른지 확인하십시오."); 반환 구성; } /** * {@link springfactorioryloader}에서 사용한 클래스를 구성하여 구성 * 후보를로드합니다. * @공장 클래스 */ Protected Class <?> getSpringFactorioryLoaderFactoryClass () {return enableAutoConfiguration.class; }여기서 나는 Meta -Inf/spring.factories에서 enableautoconfiguration의 구성을 읽은 다음 제외 및 필터링을 실행하여 조립 해야하는 클래스를 얻을 수있는 오래된 지인 -SpringFactoryiesloader를 만났습니다. 마지막으로, meta-inf/spring에서 구성된 모든 autoconfigurationImportListener를 구성하게하십시오.
개인 void fireautoconfigurationImportevents (list <string> 구성, set <string> excclusions) {list <autoconfigurationImportListener> 리스너 = getAutoconfigurationImportListeners (); if (! warners.isempty ()) {autoconfigurationImportevent event = new AutoconFigurationImportEvent (이, 구성, excclusions); for (autoconfigurationImportListener 리스너 : 리스너) {invokeawaremethods (리스너); LEARTER.ONAUTOCONFIGURINGIMPORTEVENT (이벤트); }}} 보호 목록 <AutoConfigurationImportListener> getAutoConfigurationImportListeners () {return springfactoriordoLoader.loadFactories (autoconfigurationImportListener.class, this.BeanClassLoader); }이전 링크에서, 우리는 어떤 클래스를 조립 해야하는지 결정하면되며,이 자동 조립 클래스는 언제 스프링 부츠에서 처리됩니까? 간단히 분석하겠습니다.
2.1. AbstractApplicationContext의 새로 고침 메소드 :
이 방법은 진부한 것입니다. 이 방법에주의하십시오.
// 컨텍스트에서 콩으로 등록 된 공장 프로세서를 호출합니다. InvokeBeanFactorypostprocessors (beanfactory);
다음은 BeanFactoryPostProcessor의 프로세스입니다.이 인터페이스 BeanDefinitionRegistryPostProcessor를 살펴 보겠습니다.
/ * * Copyright 2002-2010 원래 저자 또는 저자. * * Apache 라이센스에 따라 라이센스가 부여 된 버전 2.0 ( "라이센스"); * 라이센스를 준수하는 것 외에는이 파일을 사용할 수 없습니다. * 귀하는 * * http://www.apache.org/license/license/license-2.0 *에서 라이센스 사본을 얻을 수 있습니다. 적용 가능한 법률에 의해 요구되거나 서면으로 동의하지 않는 한, 라이센스에 따라 배포 된 소프트웨어 *는 "기준"에 배포됩니다. * 라이센스에 따른 특정 언어 통치 권한 및 * 제한 사항에 대한 라이센스를 참조하십시오. */package org.springframework.beans.factory.support;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;/** * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for * the registration of further bean definitions <i>before</i> regular * BeanFactoryPostProcessor detection kicks in. In particular, * BeanDefinitionRegistryPostProcessor may register further bean definitions * which in turn define BeanFactoryPostProcessor instances. * * @author Juergen Hoeller * @since 3.0.1 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor */public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { /** * Modify the application context's internal bean definition registry after its * standard initialization. All regular bean definitions will have been loaded, * but no beans will have been instantiated yet. This allows for adding further * bean definitions before the next post-processing phase kicks in. * @param registry the bean definition registry used by the application context * @throws org.springframework.beans.BeansException in case of errors */ void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;}该接口继承了BeanFactoryPostProcessor。
2.2、ConfigurationClassPostProcessor 类
该类主要处理@Configuration注解的,它实现了BeanDefinitionRegistryPostProcessor, 那么也间接实现了BeanFactoryPostProcessor,关键代码如下:
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + beanFactory); } this.factoriesPostProcessed.add(factoryId); if (!this.registriesPostProcessed.contains(factoryId)) { // BeanDefinitionRegistryPostProcessor hook apparently not supported... // Simply call processConfigurationClasses lazily at this point then. processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } enhanceConfigurationClasses(beanFactory); beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }/** * Build and validate a configuration model based on the registry of * {@link Configuration} classes. */ public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { //.....省略部分代码// Parse each @Configuration class ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size()); do { parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( 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(); Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames)); Set<String> alreadyParsedClasses = new HashSet<String>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } for (String candidateName : newCandidateNames) { if (!oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) { candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty()); // ....省略部分代码}其实这里注释已经很清楚了,我们可以清楚的看到解析每一个@ConfigurationClass的关键类是:ConfigurationClassParser,那么我们继续看一看这个类的parse方法:
public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } processDeferredImportSelectors(); }在这里大家留意一下最后一句processDeferredImportSelectors方法,在这里将会对DeferredImportSelector进行处理,这样我们就和AutoConfigurationSelectImporter结合到一起了:
private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } } }请大家关注这句代码:String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());在这里deferredImport的类型为DeferredImportSelectorHolder:
private static class DeferredImportSelectorHolder { private final ConfigurationClass configurationClass; private final DeferredImportSelector importSelector; public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) { this.configurationClass = configClass; this.importSelector = selector; } public ConfigurationClass getConfigurationClass() { return this.configurationClass; } public DeferredImportSelector getImportSelector() { return this.importSelector; } }在这个内部类里持有了一个DeferredImportSelector的引用,至此将会执行自动装配的所有操作
1)自动装配还是利用了SpringFactoriesLoader来加载META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它会经过exclude和filter等操作,最终确定要装配的类
2) 处理@Configuration的核心还是ConfigurationClassPostProcessor,这个类实现了BeanFactoryPostProcessor, 因此当AbstractApplicationContext执行refresh方法里的invokeBeanFactoryPostProcessors(beanFactory)方法时会执行自动装配
以上所述是小编给大家介绍的SpringBoot中的自动装配,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!