FireDrago
[SpringBoot] 다양한 외부 설정 조회방법 본문
Environment
스프링이 제공하는 추상화된 인터페이스이다.
Environment는 Os 환경변수, 자바 환경변수, 어플리케이션 파라미터 , 외부 설정 파일을 가리지 않고
설정값을 가져올 수 있게 해준다.
my:
datasource:
url: local.db.com
username: local_user
password: local_pw
etc:
max-connection: 1
timeout: 3500ms
options: CACHE, ADMIN
---
spring:
config:
activate:
on-profile: dev
my:
datasource:
url: dev.db.com
username: dev_user
password: dev_pw
etc:
maxConnection: 10
timeout: 60s
options: DEV, CACHE
---
spring:
config:
activate:
on-profile: prod
my:
datasource:
url: prod.db.com
username: prod_user
password: prod_pw
etc:
maxConnection: 50
timeout: 10s
options: PROD, CACHE
application.yml 파일의 설정이다. 프로필 별로 설정값이 다르게 설정되어 있다.
@Slf4j
@Data
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);
}
}
먼저 외부 설정을 저장할 MyDataSource 클래스를 만들었다.
@PostConstruct 어노테이션을 사용하여 객체가 생성된 이후 필드값을 로그출력 하도록 했다.
@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");
Integer maxConnection = env.getProperty("my.datasource.etc.max-connection", Integer.class);
Duration timeout = env.getProperty("my.datasource.etc.timeout", Duration.class);
List options = env.getProperty("my.datasource.etc.options", List.class);
return new MyDataSource(url, username, password, maxConnection, timeout, options);
}
}
@Import(MyDataSourceEnvConfig.class)
@SpringBootApplication(scanBasePackages = {"hello.datasource", "hello.pay"})
public class ExternalReadApplication {
public static void main(String[] args) {
SpringApplication.run(ExternalReadApplication.class, args);
}
}
@Configuration 클래스 에서 빈을 생성했다.
Environment 인터페이스를 주입받고,
Environment.getProperty(key, Type) 메서드에 key 값과 반환타입을 파라미터로 전달한다.
반환타입을 주면 해당 타입으로 변환해준다.
이 방식의 단점은 Environment 를 직접 주입받고, env.getProperty(key) 를 통해서 값을 꺼내는 과정을 반복해야 한다
@Value
@Value를 사용하면, 필드와 파라미터에 사용하여 원하는 값을 주입받을 수 있다.
@Value 도 내부에서는 Environment를 사용한다. ${} 를 사용한다.
@Slf4j
@Configuration
public class MyDataSourceValueConfig {
// 필드에 사용
@Value("${my.datasource.url}")
private String url;
@Value("${my.datasource.username}")
private String username;
@Value("${my.datasource.password}")
private String password;
@Value("${my.datasource.etc.max-connection}")
private int maxConnection;
@Value("${my.datasource.etc.timeout}")
private Duration timeout;
@Value("${my.datasource.etc.options}")
private List<String> options;
@Bean
public MyDataSource myDataSource1() {
return new MyDataSource(url, username, password, maxConnection, timeout, options);
}
@Bean
public MyDataSource myDataSource2(
// 파라미터에 사용
@Value("${my.datasource.url}") String url,
@Value("${my.datasource.username}") String username,
@Value("${my.datasource.password}") String password,
@Value("${my.datasource.etc.max-connection:1}") int maxConnection,
@Value("${my.datasource.etc.timeout}") Duration timeout,
@Value("${my.datasource.etc.options}") List<String> options) {
return new MyDataSource(url, username, password, maxConnection, timeout, options);
}
}
@Import(MyDataSourceValueConfig.class)
@SpringBootApplication(scanBasePackages = {"hello.datasource", "hello.pay"})
public class ExternalReadApplication {
public static void main(String[] args) {
SpringApplication.run(ExternalReadApplication.class, args);
}
}
@Value("${my.datasource.etc.max-connection:1}") int maxConnection
기본값을 사용하려면 : 뒤에 기본값을 적어준다.
@ConfigurationProperties
스프링은 외부 설정의 묶음정보를 객체로 변환하는 기능을 제공한다. 객체를 사용하면, 잘못된 타입이 들어오는 경우를
방지 할 수 있고 활용성이 더 증가한다. 이를 타입 안전한 설정 속성이라고 한다. 타입이 다르면 오류가 발생하는 것이다
@Data
@ConfigurationProperties("my.datasource")
public class MyDataSourcePropertiesV1 {
private String url;
private String username;
private String password;
private Etc etc = new Etc();
@Data
public static class Etc {
private int maxConnection;
private Duration timeout;
private List<String> options = new ArrayList<>();
}
}
@Getter
@ConfigurationProperties("my.datasource")
public class MyDataSourcePropertiesV2 {
private String url;
private String username;
private String password;
private Etc etc;
public MyDataSourcePropertiesV2(String url, String username,
String password, @DefaultValue Etc etc) {
this.url = url;
this.username = username;
this.password = password;
this.etc = etc;
}
@Getter
public static class Etc {
private int maxConnection;
private Duration timeout;
private List<String> options;
public Etc(int maxConnection, Duration timeout,
@DefaultValue("DEFAULT") List<String> options) {
this.maxConnection = maxConnection;
this.timeout = timeout;
this.options = options;
}
}
}
@ConfigurationProperties("my.datasource") 클래스에 어노테이션을 붙이면, 외부설정으로 객체를 만들 수 있다.
필드명은 외부 설정의 키 값에 맞춘다. 기본 주입 방식은 자바빈 프로퍼티 방식이다. Getter , Setter 가 필요하다.
하지만 setter는 부작용이 크므로, 생성자방식도 지원한다.
MyDataSourcePropertiesV1 : 자바빈 프로퍼티 방식
MyDataSourcePropertiesV2 : 생성자 방식
@DefaultValue : 해당 값을 찾을 수 없는 경우 기본값을 사용한다.
@DefaultValue Etc etc : etc 를 찾을 수 없을 경우 Etc 객체를 생성하고 내부에 들어가는 값은 비워둔다. ( null , 0 )
@DefaultValue("DEFAULT") List<String> options : options 를 찾을 수 없을 경우 DEFAULT 라는 이름의 값을 사용한다.
@Slf4j
@EnableConfigurationProperties(MyDataSourcePropertiesV2.class)
public class MyDataSourceConfigV2 {
private final MyDataSourcePropertiesV2 properties;
public MyDataSourceConfigV2(MyDataSourcePropertiesV2 properties) {
this.properties = properties;
}
@Bean
public MyDataSource myDataSource() {
return new MyDataSource(
properties.getUrl(),
properties.getUsername(),
properties.getPassword(),
properties.getEtc().getMaxConnection(),
properties.getEtc().getTimeout(),
properties.getEtc().getOptions());
}
}
@EnableConfigurationProperties(MyDataSourcePropertiesV2.class) :
스프링에게 사용할 @ConfigurationProperties 를 지정해준다. 이렇게 하면 스프링 빈으로 등록되고 주입받을 수 있다.
생성자 주입을 통해 주입받은 것을 볼 수 있다.
여러개의 @ConfigurationProperties 를 등록할때는 @ConfigurationPropertiesScan 을 사용한다. 범위를 지정할 수 있다.
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {}
<@ConfigurationProperties 검증>
@ConfigurationProperties 를 사용할때, 자바 빈 검증기를 사용할 수 있다.
build.gradle 에 validation을 추가해준다.
implementation 'org.springframework.boot:spring-boot-starter-validation'
@Getter
@ConfigurationProperties("my.datasource")
@Validated
public class MyDataSourcePropertiesV3 {
@NotEmpty
private String url;
@NotEmpty
private String username;
@NotEmpty
private String password;
private Etc etc;
public MyDataSourcePropertiesV3(String url, String username, String password, Etc etc) {
this.url = url;
this.username = username;
this.password = password;
this.etc = etc;
}
@Getter
public static class Etc {
@Min(1)
@Max(999)
private int maxConnection;
@DurationMin(seconds = 1)
@DurationMax(seconds = 60)
private Duration timeout;
private List<String> options;
public Etc(int maxConnection, Duration timeout, List<String> options) {
this.maxConnection = maxConnection;
this.timeout = timeout;
this.options = options;
}
}
}
@NotEmpty : url , username , password 는 항상 값이 있어야 한다. 필수 값이 된다.
@Min(1) @Max(999) maxConnection : 최소 1 , 최대 999 의 값을 허용한다.
@DurationMin(seconds = 1) @DurationMax(seconds = 60) : 최소 1, 최대 60초를 허용한다.
'프로그래밍 > SpringBoot' 카테고리의 다른 글
| [SSE] SseEmitter로 실시간 주문 상태 업데이트 구현하기 (3) | 2025.08.09 |
|---|---|
| [SpringBoot] 외부설정 (properties) (0) | 2024.05.30 |
| [SpringBoot] 스프링부트와 내장톰캣 (0) | 2024.05.23 |
