프로젝트 생성
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.2'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'hello'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//test lombok 사용
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}
tasks.named('test') {
useJUnitPlatform()
}
- 스프링 부트에서 다음 라이브러리를 선택했다.
- Lombok
- 테스트 코드에서 lombok을 사용할 수 있도록 설정을 추가했다.
Environment
외부 설정
- 설정 데이터( application.properties )
- OS 환경변수
- 자바 시스템 속성
- 커맨드 라인 옵션 인수
스프링이 지원하는 다양한 외부 설정 조회 방법
- Environment
- @Value - 값 주입
- @ConfigurationProperties - 타입 안전한 설정 속성
MyDataSource
@Slf4j
public class MyDataSource {
private String url;
private String username;
private String password;
private int maxConnection;
private Duration timeout;
private List<String> options;
public MyDataSource(String url, String username, String password, int maxConnection,
Duration timeout, List<String> options) {
this.url = url;
this.username = username;
this.password = password;
this.maxConnection = maxConnection;
this.timeout = timeout;
this.options = options;
}
@PostConstruct
public void init() {
log.info("url = {}", url);
log.info("username = {}", username);
log.info("password = {}", password);
log.info("maxConnection = {}", maxConnection);
log.info("timeout = {}", timeout);
log.info("options = {}", options);
}
}
- 필드 정보
- url , username , password : 접속 url, 이름, 비밀번호
- maxConnection : 최대 연결 수
- timeout : 응답 지연시 타임아웃
- options : 연결시 사용하는 기타 옵션들
- @PostConstruct 에서 확인을 위해 설정된 값을 출력한다.
application.properties
my.datasource.url=local.db.com
my.datasource.username=username
my.datasource.password=password
my.datasource.etc.max-connection=1
my.datasource.etc.timeout=3500ms
my.datasource.etc.options=CACHE,ADMIN
- 외부 속성은 설정 데이터( appliation.properties )를 사용한다.
- 여기서는 별도의 프로필은 사용하지 않았다. 환경에 따라서 다른 설정값이 필요하다면 각 환경에 맞는 프로필을 적용하면 된다.
참고 - properties 케밥 표기법
properties는 자바의 낙타 표기법( maxConnection )이 아니라 소문자와 - (dash)를 사용하는 케밥표기법( max-connection )을 주로 사용한다.
참고로 이곳에 자바의 낙타 표기법을 사용한다고 해서 문제가 되는 것은 아니다. 스프링은 properties 에 케밥 표기법을 권장한다.
MyDataSourceEnvConfig
@Slf4j
@Configuration
public class MyDataSourceEnvConfig {
private final Environment env;
public MyDataSourceEnvConfig(Environment env) {
this.env = env;
}
@Bean
public MyDataSource myDataSource(){
String url = env.getProperty("my.datasource.url");
String username = env.getProperty("my.datasource.username");
String password = env.getProperty("my.datasource.password");
int maxConnection = env.getProperty("my.datasource.etc.max-connection", Integer.class);
Duration timeout = env.getProperty("my.datasource.etc.timeout", Duration.class);//스프링이 MS 문자를 보고 변환 해준다
List options = env.getProperty("my.datasource.etc.options", List.class);
return new MyDataSource(url, username, password, maxConnection, timeout, options);
}
}
- MyDataSource 를 스프링 빈으로 등록하는 자바 설정이다.
- Environment를 사용하면 외부 설정의 종류와 관계없이 코드 안에서 일관성 있게 외부 설정을 조회할 수 있다.
- Environment.getProperty(key, Type) 를 호출할 때 타입 정보를 주면 해당 타입으로 변환해준다.(스프링 내부 변환기가 작동한다.)
- env.getProperty("my.datasource.etc.max-connection", Integer.class) : 문자 -> 숫자로 변환
- env.getProperty("my.datasource.etc.timeout", Duration.class) : 문자 -> Duration (기간) 변환
- env.getProperty("my.datasource.etc.options", List.class) : 문자 -> List 변환(A, B -> [A, B])
- 스프링은 다양한 타입들에 대해서 기본 변환 기능을 제공한다.
Core Features
Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use a variety of external configuration sources including Java properties files, YAML files, environment variables, a
docs.spring.io
ExternalReadApplication - 수정
@Import(MyDataSourceEnvConfig.class)
@SpringBootApplication(scanBasePackages = "hello.datasource")
public class ExternalReadApplication {
public static void main(String[] args) {
SpringApplication.run(ExternalReadApplication.class, args);
}
}
- 설정 정보를 빈으로 등록해서 사용하기 위해 @Import(MyDataSourceEnvConfig.class) 를 추가했다.
- @SpringBootApplication(scanBasePackages = "hello.datasource")
- 예제에서는 @Import 로 설정 정보를 계속 변경할 예정이므로, 설정 정보를 바꾸면서 사용하기 위해 hello.config 의 위치를 피해서 컴포넌트 스캔 위치를 설정했다.
- scanBasePackages 설정을 하지 않으면 현재 위치인 hello 패키지부터 그 하위가 모두 컴포넌트 스캔이 된다. 따라서 @Configuration 을 포함하고 있는 MyDataSourceEnvConfig 이 항상 컴포넌트 스캔의 대상이 된다.
정리
application.properties 에 필요한 외부 설정을 추가하고, Environment 를 통해서 해당 값들을 읽어서, MyDataSource를 만들었다. 향후 외부 설정 방식이 달라져도, 예를 들어서 설정 데이터 (application.properties)를 사용하다가 커맨드 라인 옵션 인수나 자바 시스템 속성으로 변경해도 애플리케이션 코드를 그대로 유지할 수 있다.
단점
이 방식의 단점은 Environment를 직접 주입받고, env.getProperty(key)를 통해서 값을 꺼내는 과정을 반복해야 한다는 점이다.
스프링은 @Value를 통해서 외부 설정값을 주입받는 더욱 편리한 기능을 제공한다
'스프링 부트(핵심 원리와 활용)' 카테고리의 다른 글
| Ch06. 외부설정과 프로필(2) - 외부 설정 사용(@ConfigurationProperties 시작) (0) | 2023.03.18 |
|---|---|
| Ch06. 외부설정과 프로필(2) - 외부 설정 사용(@Value) (0) | 2023.03.15 |
| Ch05. 외부설정과 프로필(1) - 우선순위(전체) (0) | 2023.03.15 |
| Ch05. 외부설정과 프로필(1) - 우선순위(설정 데이터) (0) | 2023.03.13 |
| Ch05. 외부설정과 프로필(1) - 설정 데이터(내부 파일 합체) (0) | 2023.03.12 |