본문 바로가기

JAVA/Spring Boot

스프링 부트 기본-#2

반응형

자동설정

  • 자동설정은 스프링 부트의 장점이며 매우 중요한 역할.
  • 스프링 부트 자동 설정은 web, h2, jdbc 등 여러개의 자동설정을 제공한다.
  • h2 의존성이 클래스 경로에 존재한다면 자동으로 인메모리 데이터베이스에 접근한다.

자동환경설정 어노테이션

  • 기존의 스프링 프레임워크를 사용했다면 의존성을 일일이 bean으로 설정했어야 한다.
  • 스프링 부트는 관련 의존성을 스타터라는 묶음으로 제공하며 수동 설정을 지양한다.

@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 {
...
}

@SpringBootApplication : 스프링 부트의 설정을 나타내는 어노테이션

  • 스프링의 @Configuration을 대체하며 스프링부트 전용으로 사용한다.

@EnableAutoConfiguration: 자동설정의 핵심 어노테이션

  • 클래스 경로에 지정된 내용을 기반으로 설정 자동화를 수행
  • 특정한 설정값을 추가하지 않을 경우 기본값으로 설정

@ComponentScan: 특정 패키지 경로를 기반으로 @Configuration에서 사용할 @Component 설정 클래스를 찾음

  • @ComponentScan의 basePackages 프로퍼티 값에 별도의 경로를 설정하지 않으면 @ComponentScan이 위치한 패키지가 루트 경로로 설정됨

@SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan 조합

@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
...
}
  • 자동 설정을 지원해주는 어노테이션은 @Import(AutoConfigurationImportSelector.class)이다.

AutoConfigurationImportSelector 클래스

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


    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }


    protected AutoConfigurationEntry getAutoConfigurationEntry(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 = getConfigurationClassFilter().filter(configurations);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationEntry(configurations, exclusions);
    }

    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;
    }

  • AutoConfigurationImportSelector 클래스는 DeferredImportSelector 인터페이스를 구현한 클래스로 오버라이드 받은 selectImports() 메서드가 자동 설정할 빈을 결정한다.
  1. getCandidateConfigurations() 메서드를 통해 META-INF/spring.factories에 정의된 자동 설정할 클래스를 먼저 불러온다.
  2. 스프링 부트 스타터를 여러개 등록하여 사용할 경우 내부에 중복된 빈이 설정될 경우가 빈번한데, 이러한 경우 제외할 설정(getExclusions())과 중복된 설정(removeDuplicates())을 제외시킨다.

빈의 등록과 자동 설정에 필요한 파일
META-INF/spring.factories: 자동 설정 타킷 클래스 목록

  • 이곳에 선언되어 있는 클래스들이 @EnableAutoConfiguration 사용시 자동 설정 타깃이 된다.
    META-INF/spring-configuration-metadata.json: 자동 설정에 사용할 프로퍼티 정의 파일
  • 미리 구현되어 있는 자동 설정에 프로퍼티만 주입시켜주면된다.
  • 별도의 환경 설정은 필요없다.
    org/springframework/boot/autoconfigure: 미리 구현해놓은 자동 설정 리스트
  • 이름은 '{특정설정의 이름}AutoConfiguration' 형식으로 지정되어 있으며 모두 자바 설정방식을 따르고 있다.

spring-boot-autoconfiguration에 미리 정의되어 있으며 지정된 프로퍼티 값을 사용하여 설정 클래스 내부의 값들을 변경할수 있다.

예) h2 자동설정

org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration
    {
      "name": "spring.h2.console.path",
      "type": "java.lang.String",
      "description": "Path at which the console is available.",
      "sourceType": "org.springframework.boot.autoconfigure.h2.H2ConsoleProperties",
      "defaultValue": "\/h2-console"
    },
  • H2 기본값은 /h2-console

application.properties에서 h2 path변경

spring.h2.console.path=/h2-test
  • 프로퍼티 값을 추가하는것만으로 자동환경 설정에 자동으로 적용된다.

자동 설정 어노테이션

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(WebServlet.class)
@ConditionalOnProperty(prefix = "spring.h2.console", name = "enabled", havingValue = "true", matchIfMissing = false)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(H2ConsoleProperties.class)
public class H2ConsoleAutoConfiguration {

    private static final Log logger = LogFactory.getLog(H2ConsoleAutoConfiguration.class);

    @Bean
    public ServletRegistrationBean<WebServlet> h2Console(H2ConsoleProperties properties,
            ObjectProvider<DataSource> dataSource) {
        String path = properties.getPath();
        String urlMapping = path + (path.endsWith("/") ? "*" : "/*");
        ServletRegistrationBean<WebServlet> registration = new ServletRegistrationBean<>(new WebServlet(), urlMapping);
        H2ConsoleProperties.Settings settings = properties.getSettings();
        if (settings.isTrace()) {
            registration.addInitParameter("trace", "");
        }
        if (settings.isWebAllowOthers()) {
            registration.addInitParameter("webAllowOthers", "");
        }
        dataSource.ifAvailable((available) -> {
            try (Connection connection = available.getConnection()) {
                logger.info("H2 console available at '" + path + "'. Database available at '"
                        + connection.getMetaData().getURL() + "'");
            }
            catch (SQLException ex) {
                // Continue
            }
        });
        return registration;
    }

}

@ConditionalOnWebApplication(type = Type.SERVLET)

  • 웹 애플리케이션일 때
    @ConditionalOnClass(WebServlet.class)
  • WebServlet.class가 클래스 경로에 있을때
    @ConditionalOnProperty(prefix = "spring.h2.console", name = "enabled", havingValue = "true", matchIfMissing = false)
  • spring.h2.console.enabled값이 true일때

@AutoConfigureAfter(DataSourceAutoConfiguration.class)

  • DataSourceAutoConfiguration.class 클래스들이 적용한 이후에 해당 자동 설정 적용

@EnableConfigurationProperties(H2ConsoleProperties.class)

  • 자동 설정 프로퍼티가 적용될때 H2ConsoleProperties 클래스 타입으로 H2 관련 프로퍼티 값을 매핑하여 사용하게 된다.
datasource.url=jdbc:h2:mem:testdb

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
##remote access
spring.h2.console.settings.web-allow-others=false
##enable trace output
spring.h2.console.settings.trace=false

컴파일에 포함되도록 H2 의존성을 설정.

compile('com.h2database:h2')
  • H2 메모리 데이터베이스는 주로 테스트용으로만 쓰인다.
  • 따라서 불필요하게 컴파일 의존성에 포함될 필요가 없다.

런타임에 의존성으로 설정

runtime('com.h2database:h2')

 

출저 - 처음배우는 스프링 부트 2
저자 - 김영재

반응형

'JAVA > Spring Boot' 카테고리의 다른 글

스프링 부트 기본설정 및 기본 테스트  (0) 2021.06.04
Swagger-UI url 변경  (0) 2021.05.31
스프링 부트 기본-#1  (0) 2020.10.15
Spring MyBatis사용 및 설정  (1) 2020.10.13
메이븐 멀티 프로젝트 구성  (0) 2020.09.04