첫 번째 연락처는 스프링의 기초가 바로 그 때 양방향 패키지를 인용, 백엔드 개발을하는 것은 우리가 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.factories
의 EnableAutoConfiguration
빈의 관련 클래스를, 두 번째는 용기 봄하는 클래스 등록을 얻는 것입니다.
클래스 수집 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
잘합니다. 원치 않는 콩의 경우, 소비자가 사용할 수 있습니다 제외 특성을.@EnableAutoConfiguration
exclude
나는 자바, 레디 스, MongoDB를, MySQL은, 커버, 무료 자바 고급 정보를 컴파일 사육사, 봄 클라우드, 두보는 높은 동시성 및 기타 자습서, 30G의 총, 자신의 콜렉션을 필요로 분산.
포털 : https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q