스프링 부트 설정 분석

 

MemoryConfig

package hello.itemservice.config;

import hello.itemservice.repository.ItemRepository;
import hello.itemservice.repository.memory.MemoryItemRepository;
import hello.itemservice.service.ItemService;
import hello.itemservice.service.ItemServiceV1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MemoryConfig {

    @Bean
    public ItemService itemService() {
        return new ItemServiceV1(itemRepository());
    }

    @Bean
    public ItemRepository itemRepository() {
        return new MemoryItemRepository();
    }

}

ItemServiceV1 , MemoryItemRepository 를 스프링 빈으로 등록하고 생성자를 통해 의존관계를 주입한다.
 참고로 여기서는 서비스와 리포지토리는 구현체를 편리하게 변경하기 위해, 이렇게 수동으로 빈을 등록했다.
 컨트롤러는 컴포넌트 스캔을 사용한다.

 

 

 

 

TestDataInit

package hello.itemservice;

import hello.itemservice.domain.Item;
import hello.itemservice.repository.ItemRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;

@Slf4j
@RequiredArgsConstructor
public class TestDataInit {

    private final ItemRepository itemRepository;

    /**
     * 확인용 초기 데이터 추가
     */
    @EventListener(ApplicationReadyEvent.class)
    public void initData() {
        log.info("test data init");
        itemRepository.save(new Item("itemA", 10000, 10));
        itemRepository.save(new Item("itemB", 20000, 20));
    }

}

 애플리케이션을 실행할 때 초기 데이터를 저장한다.
 리스트에서 데이터가 잘 나오는지 편리하게 확인할 용도로 사용한다. 
     
이 기능이 없으면 서버를 실행할 때 마다 데이터를 입력해야 리스트에 나타난다. (메모리여서 서버를 내리면 데이터가 제거된다.)
 @EventListener(ApplicationReadyEvent.class) : 스프링 컨테이너가 완전히 초기화를 다 끝내고,  실행 준비가 되었을 때 발생하는 이벤트이다. 스프링이 이 시점에 해당 애노테이션이 붙은 initData() 메서드를 호출해준다.
     참고로 이 기능 대신 @PostConstruct 를 사용할 경우 AOP 같은 부분이 아직 다 처리되지 않은 시점에 호출될 수 있기 때문에, 간혹 문제가 발생할 수 있다. 예를 들어서 @Transactional 과 관련된 AOP가 적용되지 않은 상태로 호출될 수 있다.
     @EventListener(ApplicationReadyEvent.class) 는 AOP를 포함한 스프링 컨테이너가 완전히 초기화 된 이후에 호출되기 때문에 이런 문제가 발생하지 않는다.

 

 

 

 

 

ItemServiceApplication

package hello.itemservice;

import hello.itemservice.config.*;
import hello.itemservice.repository.ItemRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;


@Import(MemoryConfig.class)
@SpringBootApplication(scanBasePackages = "hello.itemservice.web")
public class ItemServiceApplication {

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

   @Bean
   @Profile("local")
   public TestDataInit testDataInit(ItemRepository itemRepository) {
      return new TestDataInit(itemRepository);
   }

}

 @Import(MemoryConfig.class) : 앞서 설정한 MemoryConfig 를 설정 파일로 사용한다.
 scanBasePackages = "hello.itemservice.web" : 여기서는 컨트롤러만 컴포넌트 스캔을 사용하고,  나머지는 직접 수동 등록한다. 그래서 컴포넌트 스캔 경로를 hello.itemservice.web 하위로 지정했다.
 @Profile("local") : 특정 프로필의 경우에만 해당 스프링 빈을 등록한다. 여기서는 local 이라는 이름의 프로필이 사용되는 경우에만 testDataInit 이라는 스프링 빈을 등록한다. 이 빈은 앞서 본 것인데,  편의상 초기 데이터를 만들어서 저장하는 빈이다.

 

 

 

 

프로필

 

스프링은 로딩 시점에 application.properties 의 spring.profiles.active 속성을 읽어서 프로필로 사용한다.
이 프로필은 로컬(나의 PC), 운영 환경, 테스트 실행 등등 다양한 환경에 따라서 다른 설정을 할 때 사용하는 정보이다.
예를 들어서 로컬PC에서는 로컬 PC에 설치된 데이터베이스에 접근해야 하고, 운영 환경에서는 운영 데이터베이스에 접근해야 한다면 서로 설정 정보가 달라야 한다. 심지어 환경에 따라서 다른 스프링 빈을 등록해야 할 수 도 있다. 프로필을 사용하면 이런 문제를 깔끔하게 해결할 수 있다.

 

 

main 프로필

/src/main/resources 하위의 application.properties

spring.profiles.active=local

 위치의 application.properties 는 /src/main 하위의 자바 객체를 실행할 때 (주로 main() )  동작하는 스프링 설정이다. spring.profiles.active=local 이라고 하면 스프링은 local 이라는 프로필로 동작한다. 따라서 직전에 설명한 @Profile("local") 가 동작하고, testDataInit 가 스프링 빈으로 등록된다.

 

 

 

실행하면 다음과 같은 로그를 확인할 수 있다

The following 1 profile is active: "local"

 

 

참고로 프로필을 지정하지 않으면 디폴트( default ) 프로필이 실행된다.

No active profile set, falling back to 1 default profile: "default"

 

 

test 프로필

/src/test/resources 하위의 application.properties

spring.profiles.active=test

 이 위치의 application.properties 는 /src/test 하위의 자바 객체를 실행할 때 동작하는 스프링 설정이다.
 주로 테스트 케이스를 실행할 때 동작한다.
 spring.profiles.active=test 로 설정하면 스프링은 test 라는 프로필로 동작한다. 이 경우 직전에 설명한 @Profile("local") 는 프로필 정보가 맞지 않아서 동작하지 않는다. 따라서 testDataInit 이라는 스프링 빈도 등록되지 않고, 초기 데이터도 추가하지 않는다.

 

 

 

The following 1 profile is active: "test"

 프로필 기능을 사용해서 스프링으로 웹 애플리케이션을 로컬( local )에서 직접 실행할 때는 testDataInit 이 스프링 빈으로 등록된다. 따라서 등록한 초기화 데이터를 편리하게 확인할 수 있다.
 초기화 데이터 덕분에 편리한 점도 있지만, 테스트 케이스를 실행할 때는 문제가 될 수 있다. 테스트에서 이런 데이터가 들어있다면 오류가 발생할 수 있다. 예를 들어서 데이터를 하나 저장하고 전체 카운트를 확인하는데 1이 아니라 testDataInit 때문에 데이터가 2건 추가되어서 3이 되는 것이다.
 프로필 기능 덕분에 테스트 케이스에서는 test 프로필이 실행된다. 따라서 TestDataInit 는 스프링 빈으로 추가되지 않고, 따라서 초기 데이터도 추가되지 않는다.

 

 

 

참고
프로필에 대한 스프링 부트 공식 메뉴얼은 다음을 참고하자 > https://docs.spring.io/spring-boot/docs/current/reference/html/ features.html#features.profiles

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

처 : 김영환 스프링 DB2 강의 

복사했습니다!