본문으로 바로가기
반응형

개발할때와 실제 배포할때 설정값이 달라져야 하는 경우가  존재 합니다.

예를 들어 개발은 H2 db를 사용하고 배포는 mysql를 사용 하도록 하는거죠.

이때 spring의 profile을 이용해서 처리 할 수 있습니다.

속성값 불러오기

profile 설정에 앞서 특정 사용자 속성을 정의하고 이를 코드에서 불러다가 쓸수 있습니다.

@ConfigurationProperties를 이용하여 사용할 속성을 inject 받고 코드에서 이 값을 사용할 수 있습니다.

기존에 작성해 놓았던 employee 등록시 결과 화면에 출력하는 직원수를 조정해 보도록 하겠습니다.

### employee custom 속성 설정 ###
employee:
  pageSize: 5

application.yml에 위와 같이 속성을 정의합니다.

이를 값을 코드로 가져올 holder class를 하나 만듭니다.

@Component
@ConfigurationProperties(prefix="employee")
data class EmpolyeeProperty(var pageSize: Int = 1)

이 클래스를 다른곳에서 inject 받아서 사용하기 위해 @Component 를 붙여 줍니다.

그리고 가져올 속성에 대한 정보를 @ConfigurationProperties 를 이용하여 선언해 줍니다.

이때 미리 선언해 놓은 속성값과 class의 속성값의 이름으로 해당 값이 inject 됩니다.

클래스에서 기본값을 1로 해놓았지만 application.yml에서 5로 할당 했기 때문에 실제 값은 5가 됩니다.

만약 자바였다면 아래와 같이 class를 만들었어야 합니다.

@Component
@ConfigurationProperties(prefix="employee")
class EmpolyeeProperty {
    private int pageSize = 1
    
    public void setPageSize(int size) {
        pageSize = size
    }
}

@lombok을 써다면 setter는 제거 해도 되겠죠?

이제 아래와 같이 해당 속성을 사용할 곳에서 inject을 받습니다.

예제는 이전에 JPA에서 사용했던 부분을 재활용 합니다.

2020/12/29 - [개발이야기/Spring Framework] - [Spring] 스프링 DB 접근 및 활용 - JPA (2/2) with kotlin #5

@Slf4j
@Controller
@RequestMapping("/regi_complete2")
class RegiCompleteController2(
    @Autowired val employee2Repository: IEmployee2Repository,
    @Autowired val dept2Repository: IDept2Repository,
    @Autowired val employeeProperty: EmpolyeeProperty //속성값 injection
) {
       ...

        // 전체 employee 정보를 가져온다. 속성에 정의된 개수 만큼
        val empSize = employeeProperty.pageSize
        val employees = employee2Repository.findAll(PageRequest.of(0, empSize))
       
       ...
    }
}

생성자에서 inject 받은 후에 PageRequest 부분에서 해당 값을 넣습니다.

물론 RegiCompteteController 자체에서 @ConfigurationProperties를 추가하고 해당 속성의 setter를 제공해도 받아올수 있으나 이런 속성값들은 holder class를 만들어서 한곳에서 관리하는게 장점이 더 많습니다.

 

Spring profile 이용

위에서 언급했듯이 환경에 따라 속성값이 달라져야 하는경우 profile을 이용합니다.

여기서는 dev 버전에서는 h2 db를 사용하고 prod 환경에서는 mysql db를 사용하도록 꾸며 보겠습니다.

먼저 application.properties 파일을 두개로 분리합니다.

application.properties

#### h2 DB 사용 ###
spring.h2.console.enabled=true
spring.h2.console.path=/h2

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

application-prod.properties

spring.h2.console.enabled=false

#### mysql 설정 ###
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:mysql://localhost:3306/carfactory
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=carfactory
spring.datasource.password=carfactorytest1

profile을 분리하여 설정시 application-XXX.properties의 형태로 파일을 생성해야 합니다.

두가지 속성을 선택하기 위해서는 시스템 환경변수를 변경하거나,

$ export SPRING_PROFILES_ACTIVE=prod

jar 파일을 수행시킬때 argument로 넘겨주도록합니다. 

java -jar CarFactory-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

 

만약 application.yml을 사용한다면 하나의 파일안에서 '---'를 통해서 두개의 분기를 표현할 수 있습니다.

spring.h2.console.enabled: true
spring.h2.console.path: /h2
spring.datasource:
        url: jdbc:h2:mem:testdb
        driverClassName: org.h2.Driver
        username: sa
        password:

---
spring:
    profiles: prod
    h2.console.enabled: false
    datasource:
        url: jdbc:mysql://localhost:3306/carfactory
        driverClassName: com.mysql.cj.jdbc.Driver
        username: carfactory
        password: carfactorytest1    
    

@Profile 이용

실제로 dev 버전에서는 테스트용도로 사용하고, prod 버전에는 필요 없거나 반대의 경우가 발생할때 @Profile annotation을 사용합니다.

@SpringBootApplication
class CarFactoryApplication {
	@Bean
	@Profile("!prod", "dev")
	fun devDataLoader(dept2Repo: IDept2Repository, emp2Repo: IEmployee2Repository): CommandLineRunner {
		return CommandLineRunner { args ->
			val dept = dept2Repo.save(Dept2(1, "Infrastructure"))
			val employee2 = Employee2(100, "dev_admin","office","01011112222")
			employee2.dept = dept
			emp2Repo.save(employee2)
		}
	}

	@Bean
	@Profile("prod")
	fun prodDataLoader(dept2Repo: IDept2Repository, emp2Repo: IEmployee2Repository): CommandLineRunner {
		return CommandLineRunner { args ->
			val dept = dept2Repo.save(Dept2(1, "Infrastructure"))
			val employee2 = Employee2(100, "prod_admin","office","01033334444")
			employee2.dept = dept
			emp2Repo.save(employee2)
		}
	}
}

@Profile을 위와 같이 설정하면, profile에 따라 devDataLoader()나 prodDataLoader()가 선택적으로 수행됩니다.

또한 선택되지 않은 함수의 경우 아예 bean으로 만들지도 않습니다.

반응형