본문 바로가기
Spring Boot

Spring Boot 자동 설정

by byeongoo 2020. 1. 22.

1. Spring Boot 자동 설정

스프링 Boot를 시작하면 @SpringBootApplication 애노테이션을 볼 수 있습니다. 이 애노테이션을 Ctrl+마우스왼쪽클릭으로 들어가보면 다음과 같은 인터페이스를 볼 수 있습니다.

여기서 자세히 봐야할 애노테이션은 총 3가지입니다. @SpringBootConfiguration, @EnableAutoConfiguration, @ComponentScan 이 3가지입니다. 

 

스프링부트는 Bean 2번에 걸쳐서 등록을 합니다. @ComponentScan에 의해 @Component애노테이션이 붙어있는 클랙스를 Bean으로 등록하고, 두번째로 @EnableAutoConfiguration에 의해 Bean을 등록합니다.

//@SpringBootConfiguration
@Configuration
@ComponentScan
//@EnableAutoConfiguration
public class Application {
    public static void main(String[] args){

        SpringApplication application = new SpringApplication(Application.class);
        application.setWebApplicationType(WebApplicationType.NONE);
        application.run(args);

        SpringApplication.run(Application.class, args);
    }
}

위의 코드와 같이 @EnableAutoConfiguration을 주석 처리하고 앱을 실행하면 다음과 같은 에러메세지를 볼 수 있습니다. ServletWebServerFactory Bean은 @EnableAutoConfiguration이 Bean으로 등록해주기 때문에 웹 어플리케이션을 실행할 수 없습니다.

Caused by: org.springframework.context.ApplicationContextException: 
Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.

2. @EnableAutoConfiguration

 

@EnableAutoConfiguration은 스프링부트의 meta 파일을 읽어서, 미리 정의되어 있는 자바 설정 파일(@Configuration)들을 빈으로 등록하는 역할을 수행합니다. spring-boot-autoconfigure 라이브러리 안에 METE-INF 폴더를 보면 spring factories파일을 볼 수 있습니다. 이 파일에서 키 값에 대응되는 value에 클래스들을 다 읽어서 Bean으로 등록합니다. 또한 파일안에 EnableAutoConfiguration에 해당하는 설정들이 선언되어 있습니다. 이 설정도 타고 들어가서 보면 @Configuration으로 설정되어있는것을 알 수 있습니다. 

@ConditionalOn으로 시작되는 애노테이션들을 볼 수 있는데 조건에 따라 Bean을 등록하기도 하고, 등록하지 않기도합니다. 

 

바로 이렇게 @EnableAutoConfiguration을 통해 수많은 설정 파일들이 Bean으로 등록되서 웹 어플리케이션이 동작하게됩니다.

3. 자동 설정 만들기

xxx-Spring-Boot-Autoconfigure 모듈 : 자동 설정
xxx-Spring-Boot-Starter 모듈 : 필요한 의존성 정의

xxx-Spring-Boot-Starter 하나로 만들기도 합니다.

3.1 의존성 추가

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

pom.xml에 다음과 같은 의존성을 추가해줍니다. 


다중 프로젝트를 사용할 경우 디펜던시의 버전 번호를 각각의 pom.xml 파일에 정의하여 설정하여, 새로운 버전으로 업그레이드가 이루어질 경우 모든 pom.xml을변경해야합니다. 메이븐에서는 dependencyManagement를 통해 디펜던시 버전 번호를 병합할 수 있는 방안을 제공합니다. 부모 POM에서 dependencyManagement 정의를 통해 자식 POM에서 버전을 명시하지 않아도 dependency를 참조할 수 있습니다.

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.0.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

3.2 @Configuration 파일 작성

다음과 같이 Holoman 클래스와 HolomanConfiguration 클래스를 만들어줍니다.

public class Holoman {

    String name;

    int howLong;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHowLong() {
        return howLong;
    }

    public void setHowLong(int howLong) {
        this.howLong = howLong;
    }

    @Override
    public String toString(){
        return "Holoman{" + "name'" + name + '\'' + ", howLong=" + howLong + '}';
    }

}

@ConditionalOnMissingBean 애노테이션을 통해 Bean이 없을 경우만 이 Bean을 등록시켜 줍니다.

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(HolomanProperties.class)
public class HolomanConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public Holoman holoman(HolomanProperties properties){   //holo man이라는 Bean을 return하는 설정파일 만듬
        Holoman holoman = new Holoman();
        holoman.setHowLong(properties.getHowLong());
        holoman.setName(properties.getName());
        return holoman;
    }
}

다음과 같이 resources/META-INF 폴더 아래에 spring.factories 파일을 만들고 제가 만든 설정 파일을 선언해줍니다.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    hoon.byeungoo.HolomanConfiguration

이제 다른 프로젝트에서 사용할 수 있도록 install을 합니다. install 하면 jar파일이 생성될꺼고 다른 Maven프로젝트에서도 사용할 수 있도록 로컬메이븐 저장소에 설치를 합니다.

이제 다른 프로젝트를 생성하고 이 프로젝트에서 Bean을 Autowired하고 console에 값이 찍히는게 보일 것 입니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class HolomanRunner implements ApplicationRunner {

    @Autowired
    Holoman holoman;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println(holoman);
    }
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class SpringBootAutoconfigurationApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(SpringBootAutoconfigurationApplication.class);
        application.setWebApplicationType(WebApplicationType.NONE);
        application.run(args);
    }


    @Bean
    public Holoman holoman(){      
        Holoman holoman = new Holoman();
        holoman.setName("hoon");
        holoman.setHowLong(60);
        return holoman;
    }

}

 위와같이 holoman을 main에서 Bean으로 등록할 경우 자동설정에 의해 2번째 스캔될때 덮어씌워질 수 있습니다. 그래서 @ConditionalOnMissingBean 애노테이션을 통해 Bean이 없을 경우만 이 Bean을 등록시켜 준겁니다.

 

하지만 매번 이렇게 빈을 정의하는것은 매우 귀찮은 일입니다. application.properties에 값을 지정하고

@EnableConfigurationProperties(HolomanProperties.class) 애노테이션을 HolomanConfiguration 클래스에 붙여주고

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("holoman")
public class HolomanProperties {

    private String name;

    private int howLong;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHowLong() {
        return howLong;
    }

    public void setHowLong(int howLong) {
        this.howLong = howLong;
    }
}

properties로 부터 holoman의 값을 받아 올 수 있도록 해줍니다. HolomanRunner클래스에서 실행시 application.properties를 읽어 올 것입니다.

2가지 프로젝트의 패키지 구조를 보면 다음과 같습니다. spring-boot-configuration 프로젝트에서 spring-boot-autoconfiguration 프로젝트를 설정을 주입해주었습니다.