봄 부팅 @EnableAutoConfiguration 解析

첫 번째 연락처는 스프링의 기초가 바로 그 때 양방향 패키지를 인용, 백엔드 개발을하는 것은 우리가 XML에서 해당 패킷을 늘려야합니다, 콩을 제공 <context:component-scan base-package="xxx" /> 하거나 메모를 추가 @ComponentScan({ "xxx"}). 나는 매우 urgly 생각하지만, 거기에 더 나은 방법을 연구하지 않았다.

봄 부팅 할 때까지 접촉 한 후, 콩은 자동으로 두 번째 파티 패키지를 통합 할 수 발견했다. 하지만이 원칙의 실현을 보지 못했다. 최근까지, 때 인터뷰에 대해 물었다. 그래서 구현 로직에서 보았다.

 

제스처를 사용하여

첫 번째 원칙에서 사용 자세 전에 말한다.

콩에서 프로젝트 A를 정의.

패키지 com.wangzhi; 

수입 org.springframework.stereotype.Service; 

@Service 
공공  클래스 {개 
}

 

그리고이 프로젝트는 resources/META-INF/A가 아래에 이름을 만들기 위해 spring.factories다음과 같이 문서를 읽고, 문서

org.springframework.boot.autoconfigure.EnableAutoConfiguration = com.wangzhi.Dog

 

그런 다음 프로젝트 B에서 프로젝트를 항아리 패키지를 참조

다음과 같이 PROJECTA 코드는 다음과 같습니다

패키지 com.wangzhi.springbootdemo; 

수입 org.springframework.boot.SpringApplication;
수입 org.springframework.boot.autoconfigure.EnableAutoConfiguration;
수입 org.springframework.boot.autoconfigure.SpringBootApplication;
수입 org.springframework.context.ConfigurableApplicationContext;
수입 org.springframework.context.annotation.ComponentScan; 

@EnableAutoConfiguration 
공용  클래스 SpringBootDemoApplication { 

    공공  정적  무효 메인 (문자열 []에 args) { 
        ConfigurableApplicationContext 컨텍스트 = SpringApplication.run (SpringBootDemoApplication. 클래스, 인수); 
        에서 System.out.println (. context.getBean (com.wangzhi.Dog 클래스 )); 
    } 

}

 

인쇄 결과 :

com.wangzhi.Dog@3148f668

 

분석 원리

전반적으로 두 부분으로 나누어 져 있습니다 : 첫째, 모든 수집 spring.factoriesEnableAutoConfiguration빈의 관련 클래스를, 두 번째는 용기 봄하는 클래스 등록을 얻는 것입니다.

클래스 수집 bean 정의

컨테이너가 시작되면 봄, 그것은에 호출AutoConfigurationImportSelector#getAutoConfigurationEntry

보호 AutoConfigurationEntry getAutoConfigurationEntry ( 
        AutoConfigurationMetadata autoConfigurationMetadata, 
        AnnotationMetadata annotationMetadata) { 
    경우 (! {의 IsEnabled (annotationMetadata가))
         반환 EMPTY_ENTRY을; 
    } 
    // EnableAutoConfiguration注解的属性: excludeName等제외 
    AnnotationAttributes는 = 속성 하려면, getAttributes (annotationMetadata);
    // 得到所有的구성 
    목록은 <문자열> 구성 =의 getCandidateConfigurations (annotationMetadata는, 
            속성); 
    // 去重 
    구성 =removeDuplicates (구성);
    // 删除掉제외中指定的类 
    설정 <문자열> 제외 =의 getExclusions (annotationMetadata는, 속성); 
    checkExcludedClasses (구성 제외); 
    configurations.removeAll (제외); 
    구성 = 필터 (구성 autoConfigurationMetadata); 
    fireAutoConfigurationImportEvents (구성 제외); 
    반환  새로운 AutoConfigurationEntry (구성 제외); 
} 
getCandidateConfigurations会调用到方法loadFactoryNames : 

공공  정적 목록 <문자열> loadFactoryNames (<?> 클래스 factoryClass- 설정, @Nullable 클래스 로더 classLoader가) {
        // FactoryClassName이为org.springframework.boot.autoconfigure.EnableAutoConfiguration 
        문자열 FactoryClassName이 = factoryClass.getName ();
        // 该方法返回的是所有spring.factories文件中키为org.springframework.boot.autoconfigure.EnableAutoConfiguration的类路径
        돌아 loadSpringFactories (classLoader가) .getOrDefault (FactoryClassName이, Collections.emptyList ()); 
    } 


공공  정적  최종 문자열 FACTORIES_RESOURCE_LOCATION = "META-INF / spring.factories" ; 

개인  정적 지도 <문자열,리스트 <문자열 >> loadSpringFactories (@Nullable 클래스 로더 classLoader가) { 
        MultiValueMap <문자열, 문자열> 결과 =cache.get (classLoader가);
        만약 (! 결과 = 널 (null) ) {
             반환 결과; 
        } 

        시도 {이
             // 找到所有的"META-INF / spring.factories" 
            열거 <URL> URL을 = (classLoader가! = null이 ? 
                    classLoader.getResources (FACTORIES_RESOURCE_LOCATION 일) : 
                    ClassLoader.getSystemResources (FACTORIES_RESOURCE_LOCATION을)); 
            결과 = 새로운 LinkedMultiValueMap <> ();
            동안 (urls.hasMoreElements ()) { 
                URL의 URL = urls.nextElement ();
                자원 UrlResource를 = 새로운 새로운 UrlResource를 (URL)를;
                 // 키 속성과 값을 포함 HashMap의 유사한 파일의 내용, 속성을 읽어 
                속성 속성 = PropertiesLoaderUtils.loadProperties (자원)
                 에 대한 (의 Map.Entry <?> 항목 : properties.entrySet는 ()) { 
                    문자열 FactoryClassName이는 = . ((문자열) entry.getKey는 ())) (TRIM
                     // ','속성 파일을 사용할 수있는 분할 값 복수 
                    위해 StringUtils.commaDelimitedListToStringArray ((문자열 (문자열 factoryName ) entry.getValue ())) { 
                        result.add (FactoryClassName이, factoryName.trim ()); 
                    } 
                } 
            } 
            cache.put (classLoader가, 결과); 
            반환 결과를; 
        } 
        캐치 (IOException이 예) {
             던져  새로운 , IllegalArgumentException를 ( "위치에서 공장을로드 할 수 없습니다 ["+ 
                    FACTORIES_RESOURCE_LOCATION + "]" , 예); 
        } 
    }

 

컨테이너에 가입

위의 과정에서 얻은 모든 spring.factories빈의 경로에 지정된 클래스의 processGroupImports처리는 처리 될 @Import 동일한 용기에 도입 특수 논리.

공개  공극 processGroupImports () {
      (GROUPING DeferredImportSelectorGrouping : 이 본 .groupings.values ()) {
         // getImports 즉 모든 상기 획득 경로를 캡슐화 클래스 
        grouping.getImports ()을 대해 forEach (엔트리 ->.이 { 
            ConfigurationClass configurationClass가 = 이 본 .configurationClasses을 갔지 ( 
                    entry.getMetadata ()) 
            은 try {
                 // @Import 같은 프로세스 주석 
                processImports (configurationClass, asSourceClass (configurationClass) 
                        asSourceClasses (entry.getImportClassName ()) 은 false );
            }
            캐치 (BeanDefinitionStoreException 예) {
                 던져 예; 
            } 
            캐치 (Throwable를 예) {
                 던져  새로운 BeanDefinitionStoreException을 (
                         "[+ 구성 클래스에 대한 수입 후보자 처리하지 못했습니다" 
                                . configurationClass.getMetadata () 경우, getClassName () + "]" , 예를); 
            } 
        }); 
    } 
} 

개인  공극 processImports (ConfigurationClass configClass, sourceClass를 currentSourceClass, 
            컬렉션 <sourceClass를> importCandidates, 부울checkForCircularImports) { 
    ... 
    // 트래버스 수집 클래스 경로 
    에 대한 (sourceClass를 후보 : importCandidates) { 
       ... 
        // 후보는 ImportSelector ImportBeanDefinitionRegistrar 또는 다른 여기에 해당되지는 않습니다 처리 로직의 유형 인 경우
          // 후보 클래스가 아닌 또는 ImportBeanDefinitionRegistrar ImportSelector ->
                         // @Configuration AS 처리 클래스 IT를 
                        이 본 .importStack.registerImport ( 
                                currentSourceClass.getMetadata () candidate.getMetadata ()이 경우, getClassName ().); 
        // @Configuration 처리 등             
         processConfigurationClass (candidate.asConfigClass 합니다 (configClass));
   ... 
} 
            
    .. . 
}

 

그것은 결국에있을 것이다 수집 빈 클래스 정의 첫 번째 단계에서 볼 수있는 Configuration선박에 등록 된 동일한 치료.

종료

@EnableAutoConfiguration주석 초 당은 콩 패키지 비용을 간단하게 소개했다. 두 번째 당사자는 다른 응용 프로그램에서 외부 bean 정의에 노출에만 두 번째 파티 가방 제공하기 위해 계약을 spring.factories잘합니다. 원치 않는 콩의 경우, 소비자가 사용할 수 있습니다 제외 특성을.@EnableAutoConfigurationexclude

 

나는 자바, 레디 스, MongoDB를, MySQL은, 커버, 무료 자바 고급 정보를 컴파일 사육사, 봄 클라우드, 두보는 높은 동시성 및 기타 자습서, 30G의 총, 자신의 콜렉션을 필요로 분산.
포털 : https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q

추천

출처www.cnblogs.com/yuxiang1/p/11331727.html