Spring Boot 를 이용해서 어플리케이션을 만들다보면 외부의 값을 사용해야 하는 경우가 발생한다. AWS 의 특정 컴포넌트를 사용하기 위한 secret key 가 될 수도 있고 외부 API 를 사용하기 위한 API key 가 될 수도 있다. 소스코드에 하드코딩 하기 보다는 노출되어서는 안되는 설정값들을 별도의 파일에 분리하고 파일의 값을 불러오는 형태로 사용한다면 보다 안전하게 구현할 수 있다. 설정 파일은 .gitignore
을 이용하여 깃허브에 업로드하지 않도록 한다.
Spring Boot 어플리케이션을 생성하면 기본적으로 resources
디렉토리에 application.properties
파일이 생성되어 있다.
spring.datasource.hikari.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mariadb://localhost:3306/testdb
spring.datasource.hikari.username=root
spring.datasource.hikari.password=root
spring.datasource.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.datasource.jpa.properties.hibernate.format_sql=true
spring.datasource.jpa.show-sql=true
spring.datasource.jpa.generate-ddl=true
.properties
파일은 가독성도 떨어지며 수정하기 어렵다. .yml
파일을 사용하면 데이터를 계층 구조로 작성하여 보다 쉽게 작성할 수 있다.
spring:
datasource:
hikari:
driver-class-name: org.mariadb.jdbc.Driver
jdbc-url: jdbc:mariadb://localhost:3306/testdb
username: root
password: root
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
format_sql: true
show-sql: true
generate-ddl: true
참고로 .yml
을 이용하기 위해서는 SnakeYAML 라이브러리가 classpath 에 존재해야 한다. spring-boot-starter 의존성은 이 라이브러리를 기본적으로 제공해준다.
${app.name}
과 같이 ${}
내부에 값의 위치를 적어서 @Value
에 값을 주입하는 방식이다.
application.yml
external:
record-year: 2020
api:
name: kakao
key: 123123
ExternalService.java
@Service
public class ExternalService {
@Value("${external.record-year}")
private String recordYear; // 2020
@Value("${external.api.name}")
private String apiName; // kakao
@Value("${external.api.key}")
private Integer apiKey; // 123123
}
SpEL 은 Spring Expression Language 의 약자이다. Spring 에서 제공하는 특수한 표현 식으로 이러한 표현 식을 이용해 @Value
에 값을 주입할 수 있다.
@SpringBootTest
public class SpELTest {
@Value("#{1 eq 1}")
private boolean spelBoolean; // true
@Value("#{externalService.apiName eq 'kakao'}")
private String spelNameString; // "true"
@Test
void spelTest() {
assertThat(spelBoolean).isTrue();
assertThat(spelNameString).isEqualTo("true");
}
}
#{}
내부에 표현 식을 작성하여 사용한다. placeholder 방식과 다르게 다른 Spring Bean 을 참조해서 값을 주입할 수 있다. (ex. @Value("#{externalService eq 'chan'}")
)
바로 위의 예제에서 spelNameString
의 값이 boolean 이 아닌 String
으로 받아도 문제 없이 작동하였다. 즉, 값을 호출하는 쪽에서 타입을 설정할 수 있으므로 타입 안정성
이 떨어진다.