@SpringBootApplication 주해 의 사용

머리말
대부분의 설정 은 자바 클래스+주석 으로 대체 할 수 있 으 며,SpringBoot 프로젝트 에서 가장 많이 보 이 는 것 은@SpringBootApplication 주석 입 니 다.모든 SpringBoot 의 시작 클래스 에 표 시 됩 니 다.
이 주 해 는 SpringBoot 의 시작 과 자동 설정 에 어떤 영향 을 미 칩 니까?본 고 는 여러분 을 위해 그 원본 코드 를 해석 하고@SpringBootApplication 주해 의 신비 로 운 베일 을 벗 길 것 입 니 다.
본문
SpringBoot 프로젝트 의 자동 설정 에 관심 이 많아 서 소스 코드 를 배우 고 그 중의 일부 내용 을 정 리 했 습 니 다.오류 가 있 으 면 지적 해 주세요.말 을 많이 하지 않 고 소스 코드 를 직접 올 려 주세요.
@SpringBootApplication 주해 의 원본 코드 는 다음 과 같 습 니 다.

@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 @interface SpringBootApplication {
...
}
이것 은 복합 주해 로 모두 7 개의 서로 다른 주 해 를 포함 하고 다음은 이 7 개의 서로 다른 주 해 를 분석 하 는 것 을 볼 수 있다.
주해
2.1.1 주석 1:@Target({ElementType.TYPE})
주해 작용 범 위 를 나타 내 는 데 사용 되 며,TYPE 는 작용 범 위 를 클래스 나 인터페이스 로 나타 낸다.

2.1.2 주석 2:@Retention(RetentionPolicy.RUNTIME)

2.1.3 주석 3:@Documented
이 주석 은 자바 doc 에 의 해 기록 되 었 음 을 나타 낸다.
2.1.4 주석 4:@Inherited
주석 에 부모 클래스 가@SpringBootApplication 주 해 를 추가 하면 하위 클래스 도 이 주 해 를 계승 합 니 다(인터페이스 구현 클래스 가 잘못 되 었 습 니 다).
2.1.5 주석 5:@SpringBootConfiguration
바 텀 은@Configuration 주석 입 니 다.원본 코드 는 다음 과 같 습 니 다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
2.1.6 주석 6:@ComponetScan
@Componentscan 이라는 주 해 는 Spring 에서 매우 중요 합 니 다.XML 설정 의 요소@Componentscan 에 대응 하 는 기능 은 조건 에 맞 는 구성 요소(예 를 들 어@Component 와@Repository 등)나 bean 정 의 를 자동 으로 검색 하고 불 러 오 는 것 입 니 다.최종 적 으로 이 bean 정 의 를 IoC 용기 에 불 러 옵 니 다.
basePackages 등 속성 을 통 해 세분 화 된 맞 춤 형@Componentscan 자동 스 캔 범 위 를 지정 하지 않 으 면 기본 Spring 프레임 워 크 는 성명@Componentscan 이 있 는 패키지 에서 스 캔 합 니 다.따라서 SpringBoot 의 시작 클래스 는 루트 패키지 아래 에 두 는 것 이 좋 습 니 다.기본 값 으로 basePackages 를 지정 하지 않 기 때 문 입 니 다.
2.2 주석:@EnableAutoConfiguration
개인 적 으로@EnableAutoConfiguration 이라는 Annotation 의 가장 중요 한 역할 은@Import 의 도움 을 받 아 자동 설정 조건 에 맞 는 모든 bean 정 의 를 IoC 용기 에 불 러 오 는 것 으로 요약 할 수 있 습 니 다.
그 소스 코드 는 다음 과 같다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
  String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  
  Class<?>[] exclude() default {};
  
  String[] excludeName() default {};
}
@AutoConfiguration Package 와@Import(AutoConfiguration ImportSelector.class)두 개의 주 해 를 주목 해 야 합 니 다.
2.2.1 주석:@AutoConfigurationPackage
원본 코드 는 다음 과 같 습 니 다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
  String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  
  Class<?>[] exclude() default {};
  
  String[] excludeName() default {};
}
이 주해 의 핵심 은 사실 Import 주해 임 을 알 수 있 습 니 다.이 주해 가 표 시 된 클래스 에 대한 패 키 지 는 AutoConfiguration Packages 로 등록 해 야 한 다 는 뜻 입 니 다.이어서 Registrar 라 는 종 류 를 보 세 요.

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
​
    @Override
      //metadata           
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            //                  
      register(registry, new PackageImport(metadata).getPackageName());
    }
​
    @Override
    public Set<Object> determineImports(AnnotationMetadata metadata) {
      return Collections.singleton(new PackageImport(metadata));
    }
}
이 클래스 의 핵심 방법 은 register 방법 입 니 다.

private static final String BEAN = AutoConfigurationPackages.class.getName();
  
  public static void register(BeanDefinitionRegistry registry, String... packageNames) {
    if (registry.containsBeanDefinition(BEAN)) {
      BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
      ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
      constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
​    }
    else {
      GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
      beanDefinition.setBeanClass(BasePackages.class);
      beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
      beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      registry.registerBeanDefinition(BEAN, beanDefinition);
    }
}
register 방법의 논 리 는 매우 뚜렷 합 니 다.만약 에 이 bean 이 등록 되 었 다 면 구조 함수 파라미터 값 을 얻 고 가방 이름 을 추가 합 니 다.그렇지 않 으 면 새로운 bean 정 의 를 만 들 고 등록 합 니 다.@AutoConfigurationPackage 라 는 주 해 를 통 해 가방 에 있 는 모든 구성 요 소 를 등록 할 수 있 습 니 다.
2.2.2 주석:@Import(AutoConfigurationImportSelector.class)
이 주 해 는 AutoConfiguration ImportSelector 와 같은 핵심 방법 을 가 져 왔 습 니 다.selectImports 방법 으로 ImportSelector 인 터 페 이 스 를 실현 합 니 다.방법 은 pom.xml 파일 에 설 정 된 jar 패키지 와 구성 요 소 를 기반 으로 가 져 옵 니 다.그래서 방법 은 Class 전체 경로 의 String 배열 을 되 돌려 줍 니 다.되 돌아 오 는 Class 는 Spring 용기 에 의 해 관 리 됩 니 다.방법 원본 은 다음 과 같 습 니 다.

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
  if (!isEnabled(annotationMetadata)) {
    return NO_IMPORTS;
  }
  AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
      .loadMetadata(this.beanClassLoader);
  AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
      annotationMetadata);
  return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
이 방법 은 구조 도 뚜렷 하 다.우선 isEnabled 방법 으로 가 져 올 필요 가 있 는 지 판단 하고 가 져 올 필요 가 있 으 면 loadMetadata 방법 으로 설정 정 보 를 얻 고 getAutoConfigurationEntry 를 통 해 자동 으로 조립 한다.isEnabled 방법 원본 은 다음 과 같 습 니 다.

protected boolean isEnabled(AnnotationMetadata metadata) {
  if (getClass() == AutoConfigurationImportSelector.class) {
    return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
  }
  return true;
}
이 방법 은 EnableAutoConfiguration.ENABLED 를 통 해OVERRIDE_PROPERTY 이 설정 항목 은 자동 설정 이 필요 한 지 여 부 를 판단 합 니 다.기본 값 은 true 입 니 다.loadMetadata 방법 원본 코드 는 다음 과 같 습 니 다.

protected static final String PATH = "META-INF/" + "spring-autoconfigure-metadata.properties";
​
  public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
    return loadMetadata(classLoader, PATH);
  }
​
  static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
    try {
      Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
          : ClassLoader.getSystemResources(path);
      Properties properties = new Properties();
      while (urls.hasMoreElements()) {
        properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
      }
      return loadMetadata(properties);
    }
    catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
    }
  }
  static AutoConfigurationMetadata loadMetadata(Properties properties) {
    return new PropertiesAutoConfigurationMetadata(properties);
  }
이 방법 을 보면 META-INF/spring-autoconfigure-metadata.properties 의 모든 설정 정 보 를 불 러 오고 AutoConfigurationMetadata 대상 으로 포장 하여 되 돌려 줍 니 다.
주:spring-autoconfigure-metadata.properties 파일 은 spring-boot-autoconfigure-2.1.9.RELEASE.jar/META-INF 에 있 습 니 다.
getAutoConfigurationEntry 방법 원본 코드 는 다음 과 같 습 니 다.

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = filter(configurations, autoConfigurationMetadata);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}
이 방법 은 AutoConfiguration 의 주류 프로 세 스 방법 입 니 다.이 방법의 모든 줄 을 하나의 절차 로 볼 수 있 습 니 다.그러면 처리 절 차 는 다음 과 같 습 니 다.
1. @EnableAutoConfiguration 주석 을 설정 한 속성 값 getAttribute 를 불 러 오 는 방법:

protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
    String name = getAnnotationClass().getName();
    AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
    Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
        + " annotated with " + ClassUtils.getShortName(name) + "?");
    return attributes;
}
2.META-INF/spring.factories 파일 에서@EnableAutoConfiguration 으로 클래스 이름 을 key 로 완전히 제한 하 는 value,getCandidate Configurations 방법 을 얻 습 니 다.

​protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
        getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
        + "are using a custom packaging, make sure that file is correct.");
    return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}
그 중에서 SpringFactories Loader.loadFactory Names()는 주어진 클래스 로 더 를 사용 하여 META-INF/spring.factories 에서 주어진 유형의 공장 을 불 러 오 는 완전 한정 클래스 를 사용 하 는 역할 을 합 니 다.
3.무 거 워 지기;
4.제거 해 야 할 클래스 의 클래스 이름 을 가 져 옵 니 다.이 클래스 는@EnableAutoConfiguration 주석 에서 설정 할 수 있 습 니 다.
5.이 두 집합 검사 하기;
6.제거 해 야 할 종 류 를 제거 하기;
7.OnBeanCondition,OnClassCondition 등 조건 에 따라 여과(관심 이 있 으 면 깊이 이해 할 수 있다).
8.방송 이벤트,AutoConfiguration ImportListener 의 모든 실현 클래스 를 얻 은 다음 에 이 벤트 를 생 성하 여 방송 합 니 다.
9.설치 와 제거 가 필요 한 클래스 의 완전 한정 명 을 AutoConfigurationEntry 대상 으로 봉 하여 되 돌려 줍 니 다.
따라서@EnableAutoConfiguration 은 classpath 에서 모든 META-INF/spring.factories 설정 파일 을 찾 고,이 중 EnableAutoConfiguration 에 대응 하 는 설정 항목 을@Configuration 이 표 시 된 IoC 용기 설정 클래스 로 반사 실례 화하 여 IoC 용기 에 불 러 옵 니 다.
소결
상기 분석 을 통 해 알 수 있 듯 이@SpringBootApplication 주해 의 작 동 은@SpringApplicationConfiguration 성명 을 통 해 클래스 가 설정 클래스 로 표시 되 어 AnnotationConfigApplication Context 에서 스 캔 되 고 Spring 용 기 를 초기 화 합 니 다.
@EnableAutoConfiguration 을 통 해 필요 한 구성 요 소 를 스 캔 하고 걸 러 내 고 불 러 옵 니 다.@Component Scan 을 통 해@Component 와 그 하위 주석 이 표 시 된 모든 종 류 를 검색 하고 등록 합 니 다.이러한 주해 의 공동 운영 은 springboot 프로젝트 의 강력 한 자동 설정 능력 을 실현 하 였 다.
이상 은@SpringBootApplication 주해 의 사용 에 대한 상세 한 내용 입 니 다.@SpringBootApplication 주해 의 사용 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 해 주 십시오!

좋은 웹페이지 즐겨찾기