You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
etc를 찾을 수 없을 경우 Etc 객체를 생성하고 내부에 들어가는 값은 비워둔다. (null, 0)
@DefaultValue("DEFAULT") List<String> options
options를 찾을 수 없을 경우 DEFAULT라는 이름의 값을 사용한다.
참고:@ConstructorBinding
스프링 부트 3.0 이전에는 생성자 바인딩 시에 @ConstructorBinding 애노테이션을 필수로 사용해야 했다.
스프링 부트 3.0 부터는 생성자가 하나일 때는 생략할 수 있다. 생성자가 둘 이상인 경우에는 사용할 생성자에 @ConstructorBinding 애노테이션을 적용하면 된다.
application.properties에 필요한 외부 설정을 추가하고, @ConfigurationProperties의 생성자 주입을 통해서 값을 읽어들였다. Setter가 없으므로 개발자가 중간에 실수로 값을 변경하는 문제가 발생하지 않는다.
문제
타입과 객체를 통해서 숫자에 문자가 들어오는 것 같은 기본적인 타입 문제들은 해결이 되었다. 그런데 타입은 맞는데 숫자의 범위가 기대하는 것과 다르면 어떻게 될까? 예를 들어서 max-connection의 값을 0으로 설정하면 커넥션이 하나도 만들어지지 않는 심각한 문제가 발생한다고 가정해보자. max-connection은 최소 1이상으로 설정하지 않으면 애플리케이션 로딩 시점에 예외를 발생시켜서 빠르게 문제를 인지할 수 있도록 하고싶다.
@ConfigurationProperties를 통해서 숫자가 들어가야 하는 부분에 문자가 입력되는 문제와 같은 타입이 맞지 않는 데이터를 입력하는 문제는 예방할 수 있다. 그런데 문제는 숫자의 범위라던가, 문자의 길이 같은 부분은 검증이 어 렵다.
예를 들어서 최대 커넥션 숫자는 최소 1 ~최대 999 라는 범위를 가져야 한다면 어떻게 검증할 수 있을까? 이메일을 외부 설정에 입력했는데, 만약 이메일 형식에 맞지 않는다면 어떻게 검증할 수 있을까?
개발자가 직접 하나하나 검증 코드를 작성해도 되지만, 자바에는 자바 빈 검증기(java bean validation)이라는 훌륭한 표준 검증기가 제공된다.
@ConfigurationProperties은 자바 객체이기 때문에 스프링이 자바 빈 검증기를 사용할 수 있도록 지원한다.
자바 빈 검증기를 사용하려면 spring-boot-starter-validation이 필요하다. build.gradle에 다음 코드를 추가하자.
패키지 이름에 org.hibernate.validator로 시작하는 것은 자바 표준 검증기에서 아직 표준화 된 기능은 아니고, 하이버네이트 검증기라는 표준 검증기의 구현체에서 직접 제공하는 기능이다. 대부분 하이버네이트 검증기를 사용하므로 이 부분이 크게 문제가 되지는 않는다.
ConfigurationProperties 덕분에 타입 안전하고, 또 매우 편리하게 외부 설정을 사용할 수 있다. 그리고 검증기 덕분에 쉽고 편리하게 설정 정보를 검증할 수 있다.
가장 좋은 예외는 컴파일 예외, 그리고 애플리케이션 로딩 시점에 발생하는 예외이다. 가장 나쁜 예외는 고객 서비스 중에 발생하는 런타임 예외이다.
ConfigurationProperties 장점
외부 설정을 객체로 편리하게 변환해서 사용할 수 있다.
외부 설정의 계층을 객체로 편리하게 표현할 수 있다.
외부 설정을 타입 안전하게 사용할 수 있다.
검증기를 적용할 수 있다.
0x04. YAML
YAML
스프링은 설정 데이터를 사용할 때 application.properties 뿐만 아니라 application.yml 이라는 형식도 지원한다.
YAML
YAML(YAML Ain't Markup Language)은 사람이 읽기 좋은 데이터 구조를 목표로 한다. 확장자는 yaml , yml 이다. 주로 yml 을 사용한다.
application.properties 예시
application.yml 예시
YAML의 가장 큰 특징은 사람이 읽기 좋게 계층 구조를 이룬다는 점이다.
YAML은 space (공백)로 계층 구조를 만든다. space 는 1칸을 사용해도 되는데, 보통 2칸을 사용한다. 일관성있게 사용하지 않으면 읽기 어렵거나 구조가 깨질 수 있다.
구분 기호로 : 를 사용한다. 만약 값이 있다면 이렇게 key: value: 이후에 공백을 하나 넣고 값을 넣어주면 된다.
스프링은 YAML의 계층 구조를 properties 처럼 평평하게 만들어서 읽어들인다. 쉽게 이야기해서 위의 application.yml 예시는 application.properties 예시처럼 만들어진다.
실행해보면 application.yml 에 입력한 설정 데이터가 조회되는 것을 확인할 수 있다.
주의 application.properties , application.yml 을 같이 사용하면 application.properties가 우선권을 가진다. 이것을 둘이 함께 사용하는 것은 일관성이 없으므로 권장하지 않는다.
참고로 실무에서는 설정 정보가 많아서 보기 편한 yml 을 선호한다.
프로필과 외부 설정을 사용해서 각 환경마다 설정값을 다르게 적용하는 것은 이해했다.
그런데 설정값이 다른 정도가 아니라 각 환경마다 서로 다른 빈을 등록해야 한다면 어떻게 해야할까?
예를 들어서 결제 기능을 붙여야 하는데, 로컬 개발 환경에서는 실제 결제가 발생하면 문제가 되니 가짜 결제 기능이 있는 스프링 빈을 등록하고, 운영 환경에서는 실제 결제 기능을 제공하는 스프링 빈을 등록한다고 가정해보자.
packageorg.springframework.context.annotation;
...
@Conditional(ProfileCondition.class)
public @interface Profile {
String[] value();
}
@Profile 은 특정 조건에 따라서 해당 빈을 등록할지 말지 선택한다. 어디서 많이 본 것 같지 않은가? 바로 @Conditional이다.
코드를 보면 @Conditional(ProfileCondition.class) 를 확인할 수 있다.
스프링은 @Conditional 기능을 활용해서 개발자가 더 편리하게 사용할 수 있는 @Profile 기능을 제공하는 것이다.
정리 @Profile 을 사용하면 각 환경 별로 외부 설정 값을 분리하는 것을 넘어서, 등록되는 스프링 빈도 분리할 수 있다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
3.2. 외부설정 사용 - @ConfigurationProperties 생성자
@ConfigurationProperties는 Getter, Setter를 사용하는 자바빈 프로퍼티 방식이 아니라 생성자를 통해서 객체를 만드는 기능도 제공한다. 다음 코드를 통해서 확인해보자.MyDataSourcePropertiesV2
@DefaultValue Etc etcetc를 찾을 수 없을 경우Etc객체를 생성하고 내부에 들어가는 값은 비워둔다. (null,0)@DefaultValue("DEFAULT") List<String> optionsoptions를 찾을 수 없을 경우DEFAULT라는 이름의 값을 사용한다.MyDataSourcePropertiesV2를 사용해보자.MyDataSourceConfigV2
MyDataSourcePropertiesV2를 적용하고 빈을 등록한다. 기존 코드와 크게 다르지 않다.ExternalReadApplication - 수정
@Import(MyDataSourceConfigV1.class)를 주석처리한다.@Import(MyDataSourceConfigV2.class)를 추가한다.실행 결과
정리
application.properties에 필요한 외부 설정을 추가하고,@ConfigurationProperties의 생성자 주입을 통해서 값을 읽어들였다.Setter가 없으므로 개발자가 중간에 실수로 값을 변경하는 문제가 발생하지 않는다.문제
타입과 객체를 통해서 숫자에 문자가 들어오는 것 같은 기본적인 타입 문제들은 해결이 되었다. 그런데 타입은 맞는데 숫자의 범위가 기대하는 것과 다르면 어떻게 될까? 예를 들어서
max-connection의 값을0으로 설정하면 커넥션이 하나도 만들어지지 않는 심각한 문제가 발생한다고 가정해보자.max-connection은 최소 1이상으로 설정하지 않으면 애플리케이션 로딩 시점에 예외를 발생시켜서 빠르게 문제를 인지할 수 있도록 하고싶다.3.3. 외부설정 사용 - @ConfigurationProperties 검증
@ConfigurationProperties를 통해서 숫자가 들어가야 하는 부분에 문자가 입력되는 문제와 같은 타입이 맞지 않는 데이터를 입력하는 문제는 예방할 수 있다. 그런데 문제는 숫자의 범위라던가, 문자의 길이 같은 부분은 검증이 어 렵다.예를 들어서 최대 커넥션 숫자는 최소 1 ~최대 999 라는 범위를 가져야 한다면 어떻게 검증할 수 있을까? 이메일을 외부 설정에 입력했는데, 만약 이메일 형식에 맞지 않는다면 어떻게 검증할 수 있을까?
개발자가 직접 하나하나 검증 코드를 작성해도 되지만, 자바에는 자바 빈 검증기(java bean validation)이라는 훌륭한 표준 검증기가 제공된다.
@ConfigurationProperties은 자바 객체이기 때문에 스프링이 자바 빈 검증기를 사용할 수 있도록 지원한다.자바 빈 검증기를 사용하려면
spring-boot-starter-validation이 필요하다.build.gradle에 다음 코드를 추가하자.build.gradle검증기를 추가해서
ConfigurationProperties을 만들어보자.MyDataSourcePropertiesV3@NotEmptyurl,username,password는 항상 값이 있어야 한다. 필수 값이 된다.@Min(1) @Max(999) maxConnection: 최소1, 최대999의 값을 허용한다.@DurationMin(seconds = 1) @DurationMax(seconds = 60): 최소 1, 최대 60초를 허용한다.jakarta.validation.constraints.Max패키지 이름에
jakarta.validation으로 시작하는 것은 자바 표준 검증기에서 지원하는 기능이다.org.hibernate.validator.constraints.time.DurationMax패키지 이름에
org.hibernate.validator로 시작하는 것은 자바 표준 검증기에서 아직 표준화 된 기능은 아니고, 하이버네이트 검증기라는 표준 검증기의 구현체에서 직접 제공하는 기능이다. 대부분 하이버네이트 검증기를 사용하므로 이 부분이 크게 문제가 되지는 않는다.MyDataSourceConfigV3MyDataSourceConfigV3은 기존 코드와 크게 다르지 않다.ExternalReadApplication- 수정@Import(MyDataSourceConfigV2.class)를 주석처리한다.@Import(MyDataSourceConfigV3.class)를 추가한다.값이 검증 범위를 넘어서게 설정해보자
그러면 애플리케이션 로딩 시점에 다음과 같은 오류 메시지를 확인 할 수 있다.
maxConnection=0으로 설정한 예정상 실행 결과
정리
ConfigurationProperties덕분에 타입 안전하고, 또 매우 편리하게 외부 설정을 사용할 수 있다. 그리고 검증기 덕분에 쉽고 편리하게 설정 정보를 검증할 수 있다.가장 좋은 예외는 컴파일 예외, 그리고 애플리케이션 로딩 시점에 발생하는 예외이다. 가장 나쁜 예외는 고객 서비스 중에 발생하는 런타임 예외이다.
ConfigurationProperties 장점
0x04. YAML
YAML
스프링은 설정 데이터를 사용할 때
application.properties뿐만 아니라application.yml이라는 형식도 지원한다.YAML
YAML(YAML Ain't Markup Language)은 사람이 읽기 좋은 데이터 구조를 목표로 한다. 확장자는
yaml,yml이다. 주로yml을 사용한다.application.properties예시application.yml예시YAML의 가장 큰 특징은 사람이 읽기 좋게 계층 구조를 이룬다는 점이다.YAML은space(공백)로 계층 구조를 만든다.space는 1칸을 사용해도 되는데, 보통 2칸을 사용한다. 일관성있게 사용하지 않으면 읽기 어렵거나 구조가 깨질 수 있다.:를 사용한다. 만약 값이 있다면 이렇게key: value:이후에 공백을 하나 넣고 값을 넣어주면 된다.스프링은 YAML의 계층 구조를
properties처럼 평평하게 만들어서 읽어들인다. 쉽게 이야기해서 위의application.yml예시는application.properties예시처럼 만들어진다.적용
프로젝트에 적용해보자.
application.properties를 사용하지 않도록 파일 이름을 변경하자.application.properties→application_backup.propertiessrc/main/resources/application.yml를 생성하자.실행해보면
application.yml에 입력한 설정 데이터가 조회되는 것을 확인할 수 있다.YML과 프로필
YML에도 프로필을 적용할 수 있다.
application.ymlyml은---dash(-) 3개를 사용해서 논리 파일을 구분한다.spring.config.active.on-profile을 사용해서 프로필을 적용할 수 있다.application.properties와 동일하다.0x05. @Profile
프로필과 외부 설정을 사용해서 각 환경마다 설정값을 다르게 적용하는 것은 이해했다.
그런데 설정값이 다른 정도가 아니라 각 환경마다 서로 다른 빈을 등록해야 한다면 어떻게 해야할까?
예를 들어서 결제 기능을 붙여야 하는데, 로컬 개발 환경에서는 실제 결제가 발생하면 문제가 되니 가짜 결제 기능이 있는 스프링 빈을 등록하고, 운영 환경에서는 실제 결제 기능을 제공하는 스프링 빈을 등록한다고 가정해보자.
PayClient
LocalPayClient
ProdPayClient
OrderService
PayClient를 사용하는 부분이다. 상황에 따라서LocalPayClient또는ProdPayClient를 주입받는다.PayConfig
@Profile애노테이션을 사용하면 해당 프로필이 활성화된 경우에만 빈을 등록한다.default프로필(기본값)이 활성화 되어 있으면LocalPayClient를 빈으로 등록한다.prod프로필이 활성화 되어 있으면ProdPayClient를 빈으로 등록한다.RunOrder
ApplicationRunner인터페이스를 사용하면 스프링은 빈 초기화가 모두 끝나고 애플리케이션 로딩이 완료되는 시점에run(args)메서드를 호출해준다.ExternalReadApplication 변경
hello.pay패키지를 추가하자.프로필 없이 실행
No active profile set, falling back to 1 default profile: "default" LocalPayClient 빈 등록 ... 로컬 결제 money=1000default프로필이 사용된다.default프로필이 사용되면LocalPayClient가 빈으로 등록되는 것을 확인할 수 있다.prod 프로필 실행
--spring.profiles.active=prod 프로필 활성화 적용The following 1 profile is active: "prod" ProdPayClient 빈 등록 ... 운영 결제 money=1000prod프로필을 적용했다.prod프로필이 사용되면ProdPayClient가 빈으로 등록되는 것을 확인할 수 있다.@Profile의 정체
@Profile은 특정 조건에 따라서 해당 빈을 등록할지 말지 선택한다. 어디서 많이 본 것 같지 않은가? 바로@Conditional이다.코드를 보면
@Conditional(ProfileCondition.class)를 확인할 수 있다.스프링은
@Conditional기능을 활용해서 개발자가 더 편리하게 사용할 수 있는@Profile기능을 제공하는 것이다.정리
@Profile을 사용하면 각 환경 별로 외부 설정 값을 분리하는 것을 넘어서, 등록되는 스프링 빈도 분리할 수 있다.Beta Was this translation helpful? Give feedback.
All reactions