Java 프레임워크 학습 04(SpringBoot 자동 조립 원리)

1. SpringBoot 자동 조립이란 무엇입니까?
2. SpringBoot는 자동 조립을 어떻게 구현합니까? 주문형 로딩을 달성하는 방법은 무엇입니까?
3. 스타터를 구현하는 방법은 무엇입니까?

머리말

Spring을 사용해 본 친구들은 XML 구성에 지배당하는 것에 대한 두려움이 있을 것입니다. Spring이 나중에 주석 기반 구성을 도입하더라도 특정 Spring 기능을 활성화하거나 타사 종속성을 도입할 때 명시적 구성을 위해 여전히 XML 또는 Java를 사용해야 합니다.

예를 들어. Spring Boot 없이 RestFul 웹 서비스를 작성할 때 먼저 다음과 같이 구성해야 합니다.

@Configuration
public class RESTConfiguration
{
    
    
    @Bean
    public View jsonTemplate() {
    
    
        MappingJackson2JsonView view = new MappingJackson2JsonView();
        view.setPrettyPrint(true);
        return view;
    }

    @Bean
    public ViewResolver viewResolver() {
    
    
        return new BeanNameViewResolver();
    }
}

스프링-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context/ http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc/ http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.howtodoinjava.demo" />
    <mvc:annotation-driven />

    <!-- JSON Support -->
    <bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
    <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>

</beans>

그러나 Spring Boot 프로젝트의 경우 구성 없이 아래의 기본 메서드를 시작하기만 하면 관련 종속성을 추가하면 됩니다.

@SpringBootApplication
public class DemoApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(DemoApplication.class, args);
    }
}

application.properties또한 포트 번호 변경 , JPA 속성 구성 등과 같은 Spring Boot의 전역 구성 파일을 통해 application.yml프로젝트를 설정할 수 있습니다 . Spring Boot가 사용하기에 멋진 이유는 무엇입니까? 이것은 자동 배선 덕분입니다. 자동 조립은 Spring Boot의 핵심이라고 할 수 있는데 자동 조립이란 무엇입니까?

1. SpringBoot 자동 조립이란 무엇입니까?

이제 자동 어셈블리와 관련하여 일반적으로 Spring Boot와 연결됩니다. 그러나 사실 Spring Framework는 이미 이 기능을 구현하고 있다. Spring Boot는 이를 기반으로 했을 뿐이며, SPI이를 통해 더욱 최적화되었습니다.

SpringBoot는 다음을 규정하는 일련의 인터페이스 사양을 정의합니다. SpringBoot는 시작 시 외부에서 참조되는 jar 패키지의 META-INF/spring.factories 파일을 스캔하고 파일에 구성된 유형 정보를 Spring 컨테이너(여기서는 JVM과 관련됨)로 로드합니다. 클래스 로딩 메커니즘 및 Spring의 컨테이너 지식) 클래스에 정의된 다양한 작업을 수행합니다. 외부 jar의 경우 SpringBoot에서 정의한 표준에 따라 자체 기능을 SpringBoot에 설치하기만 하면 됩니다.

Spring Boot가 없으면 타사 종속성을 도입해야 하는 경우 수동 구성이 필요하며 이는 매우 번거로운 작업입니다. 그러나 Spring Boot에서는 하나를 직접 도입할 수 있습니다 starter. 예를 들어 프로젝트에서 redis를 사용하려는 경우 해당 스타터를 프로젝트에서 직접 가져올 수 있습니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

스타터를 도입한 후 몇 가지 주석과 몇 가지 간단한 구성을 통해 타사 구성 요소에서 제공하는 기능을 사용할 수 있습니다.

자동 조립은 다음과 같이 간단하게 이해할 수 있습니다. 주석 또는 간단한 구성을 통해 Spring Boot의 도움으로 특정 기능을 실현할 수 있습니다.

2. SpringBoot는 자동 조립을 어떻게 구현합니까?

먼저 SpringBoot 의 핵심 주석을 살펴보겠습니다 SpringBootApplication.

b

아마도 주석 모음 @SpringBootApplication으로 간주될 수 있습니다. @Configuration、@EnableAutoConfiguration、@ComponentScanSpringBoot 공식 웹 사이트에 따르면 이 세 가지 주석의 기능은 다음과 같습니다.

  • @EnableAutoConfiguration: SpringBoot의 자동 구성 메커니즘 활성화
  • @Configuration: 컨텍스트에서 추가 빈을 등록하거나 다른 구성 클래스를 가져올 수 있습니다.
  • @ComponentScan: @Component(@Service, @Controller) 주석이 달린 빈을 스캔합니다. 주석은 기본적으로 시작 클래스가 있는 패키지 아래의 모든 클래스를 스캔합니다. 일부 빈을 스캔하지 않도록 사용자 정의할 수 있습니다. 아래 이미지와 같이 컨테이너에서 제외 TypeExcludeFilter됩니다 AutoConfigurationExcludeFilter.

여기에 이미지 설명 삽입

@EnableAutoConfiguration자동조립을 구현하기 위한 중요한 주석으로 이 주석부터 시작하겠습니다.

3. @EnableAutoConfiguration: 자동 조립을 위한 핵심 주석

EnableAutoConfiguration참고로 자동조립의 핵심기능 구현은 사실 AutoConfigurationImportSelector클래스를 통해서입니다.

@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
@Import({
    
    AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
    
    
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {
    
    };

    String[] excludeName() default {
    
    };
}

이제 AutoConfigurationImportSelector수업이 무엇을 하는지 분석하는 데 집중하시겠습니까?

AutoConfigurationImportSelector: autowiring 클래스 로드

AutoConfigurationImportSelector클래스 상속 시스템은 다음과 같습니다.

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    
    

}

public interface DeferredImportSelector extends ImportSelector {
    
    

}

public interface ImportSelector {
    
    
    String[] selectImports(AnnotationMetadata var1);
}

ImportSelectorAutoConfigurationImportSelector 클래스가 인터페이스를 구현하고 selectImports이 인터페이스의 메서드 도 구현하는 것을 볼 수 있습니다 .이 메서드는 주로 IoC 컨테이너에 로드해야 하는 모든 적합한 클래스의 정규화된 클래스 이름을 얻는 데 사용됩니다 .

private static final String[] NO_IMPORTS = new String[0];

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    
    
        // <1>.判断自动装配开关是否打开
        if (!this.isEnabled(annotationMetadata)) {
    
    
            return NO_IMPORTS;
        } else {
    
    
          //<2>.获取所有需要装配的bean
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

getAutoConfigurationEntry()여기서는 주로 자동 구성 클래스 로드를 담당하는 메서드 에 집중해야 합니다 .

메서드 호출 체인은 다음과 같습니다.

이제 여기에 이미지 설명 삽입
결합된 소스 코드와 함께 getAutoConfigurationEntry()자세히 분석해 보겠습니다 .

private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
    
    
        //<1>.
        if (!this.isEnabled(annotationMetadata)) {
    
    
            return EMPTY_ENTRY;
        } else {
    
    
            //<2>.
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //<3>.
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //<4>.
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

1 단계:

자동 조립 스위치가 켜져 있는지 확인합니다. 기본값 spring.boot.enableautoconfiguration=true, application.properties또는 에서 application.yml설정할 수 있습니다.

여기에 이미지 설명 삽입

2 단계:

EnableAutoConfiguration 주석을 exclude가져 오는 데 사용됩니다 excludeName.

여기에 이미지 설명 삽입

3단계

autowired가 필요한 모든 구성 클래스를 가져오십시오.META-INF/spring.factories

spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

여기에 이미지 설명 삽입

아래 그림에서 이 파일의 구성 내용을 읽은 것을 볼 수 있습니다. XXXAutoConfiguration의 역할은 필요에 따라 구성 요소를 로드하는 것입니다.

여기에 이미지 설명 삽입

이 종속성을 META-INF/spring.factories읽을 뿐만 아니라 Spring Boot Starter 아래의 모든 META-INF/spring.factories를 읽습니다.

druid따라서 데이터베이스 연결 풀의 Spring Boot Starter가 META-INF/spring.factories 파일을 생성하는 것을 명확하게 볼 수 있습니다 .

Spring Boot Starter를 직접 생성하려면 이 단계가 필수적입니다.

여기에 이미지 설명 삽입

4단계:

이 시점에서 면접관은 다음과 같이 질문할 수 있습니다. " spring.factories시스템에 너무 많은 구성이 있는데 시작할 때마다 모두 로드해야 합니까?".

분명히 이것은 비현실적입니다. 디버깅 후 구성 값이 작아진 것을 확인할 수 있습니다.

여기에 이미지 설명 삽입

이 단계는 심사를 거쳐 @ConditionalOnXXX모든 조건이 충족되고 클래스가 적용되기 때문입니다.

@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({
    
     RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
    
    
}

관심 있는 사람들은 Spring Boot에서 제공하는 조건부 주석에 대해 자세히 알아볼 수 있습니다.

  • @ConditionalOnBean: 컨테이너에 지정된 Bean이 있는 경우
  • @ConditionalOnMissingBean: 컨테이너에 지정된 빈이 없을 때
  • @ConditionalOnSingleCandidate: 지정된 Bean이 컨테이너에 하나만 있는 경우 또는 여러 개 있지만 선호하는 Bean을 지정하는 경우
  • @ConditionalOnClass: 클래스 경로에 지정된 클래스가 있는 경우
  • @ConditionalOnMissingClass: 클래스 경로에 지정된 클래스가 없을 때
  • @ConditionalOnProperty: 지정된 속성에 지정된 값이 있는지 여부
  • @ConditionalOnResource: 클래스 경로에 지정된 값이 있는지 여부
  • @ConditionalOnExpression: SpEL 표현식을 판단 조건으로 함
  • @ConditionalOnJava: 판단 조건으로 Java 버전 기준
  • @ConditionalOnJndi: 차이는 JNDI가 존재하는 조건으로 지정된 위치에 있음
  • @ConditionalOnNotWebApplication: 현재 프로젝트가 웹 프로젝트가 아닌 경우
  • @ConditionalOnWebApplication: 현재 프로젝트가 웹 프로젝트인 조건

4. 스타터 구현 방법

가짜 트릭을 연습하지 않고 말만 하고 커스텀 스레드 풀을 실현하기 위해 지금 스타터를 시작합시다.

첫 번째 단계는 threadpool-spring-boot-starter프로젝트를 만드는 것입니다.

여기에 이미지 설명 삽입

두 번째 단계는 Spring Boot 관련 종속성을 도입하는 것입니다.

여기에 이미지 설명 삽입

세 번째 단계는 ThreadPoolAutoConfiguration을 만드는 것입니다.

여기에 이미지 설명 삽입

네 번째 단계는 threadpool-spring-boot-starter 프로젝트의 리소스 패키지 아래에 META-INF/spring.factories 파일을 생성하는 것입니다.

여기에 이미지 설명 삽입

마지막 새 프로젝트 가져오기threadpool-spring-boot-starter

여기에 이미지 설명 삽입

테스트 통과! ! !

여기에 이미지 설명 삽입

요약하다

Spring Boot는 최종 로딩 에서 자동 구성 클래스를 통해 자동 조립을 활성화하여 자동 조립을@EnableAutoConfiguration 구현합니다.SpringFactoriesLoaderMETA-INF/spring.factories

자동 구성 클래스는 실제로 @Conditional요청 시 로드되는 구성 클래스입니다. 적용하려면 spring-boot-starter-xxx패키지를 가져와서 시작 종속성을 구현해야 합니다.

추천

출처blog.csdn.net/ldy007714/article/details/130619955