@Value
어노테이션을 사용하면 쉽게 프로퍼티 값을 가져올 수 있다.
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class EmailService {
@Value("${email-address.business-manager}")
private String businessManagerEmail;
// ......
}
하지만 이렇게 사용하는 것을 추천하지 않는데 이 접근법의 단점으로는
복잡한 표현식이나 다중 프로퍼티를 다루기 어렵습니다. 이로 인해 특정한 프로퍼티 값을 계산하는 등의 작업을 처리하기에는 한계가 있다.
그리고 테스트 가능성을 망치게되는데, 프로퍼티들은 스프링에 의해 자동 주입될 것이므로 먼저 실행되는 테스트에 스프링 컨텍스트가 필요해진다. (이것은 단위테스트를 느리게 만든다.)
그리고 다른 프로퍼티를 사용해 테스트를 사용하려면? 일반적으로 테스트를 위해 별도의 application 프로퍼티를 가질 수 있지만 지저분해질 수 있다.
이를 해결하기 위해 @Autowired 어노테이션을 사용해서 하나 씩 생성자 주입하는 방법이 있지만 생성자가 길어지고 지저분해지게 된다.
마지막으로 @Value는 접근 방식의 유연성이 떨어지고 데이터 검증을 위한 지원 기능이 내장되어 있지 않다는 점이다.
@ConfigurationProperties
를 사용하자.그럼 뭘 사용하면 될까?
@ConfigurationProperties
는 프로퍼티를 분리하고 외부화 하는 기능을 제공한다.
email-address:
education-manager: apple@gmail.com
business-manager: banana@gmail.com
error-recipient: watermelon@gmail.com
@Getter
@Setter
@Validated
@ConfigurationProperties(prefix = "email-address")
@Configuration
public class EmailPropertiesConfig {
@NotBlank
private String educationManager;
@NotBlank
private String businessManager;
@NotBlank
private String errorRecipient;
}
@Slf4j
@Service
public class EmailService {
private final GroupRepository groupRepository;
private final JavaMailSender mailSender;
private final EmailPropertiesConfig emailProperties;
public EmailService(GroupRepository groupRepository, JavaMailSender mailSender, EmailPropertiesConfig emailProperties) {
this.groupRepository = groupRepository;
this.mailSender = mailSender;
this.emailProperties = emailProperties;
}
// ...
}
이렇게 configuration으로 분리해서 프로퍼티를 한 곳에서 POJO 클래스로 그룹화하여 관리할 수 있으며, 타입 안정성과 IDE 지원 등의 이점을 누릴 수 있다.
@Validated
어노테이션을 사용해서 유효성 검사를 적용할 수 있다. 프로퍼티가 로드되기 전에 필수 형식을 준수하는지 확인할 수 있다.유효성 검사를 진행할 수 있다. 이 유효성 검사를 충족하지 못할 경우 해당 빈이 생성되고 주입될 때 유효성 검사를 실패하게 되어 애플리케이션이 실행 중지 된다.
만약
@Value
로 프로퍼티를 주입받고 있는데 해당 프로퍼티의 값이 null이거나 empty이면 애플리케이션에서 해당 프로퍼티를 받아서 돌아가는 메서드가 실행될 때 NPE가 발생하게 된다. 이를 방어하기 위해@Value
로 주입받은 필드를 사용하기 전에 null 체크를 수행해야 하는데 @Value가 많아질 수록 코드도 길어지게 된다…
@ConfigurationProperties
인스턴스는 스프링 컨텍스트에 로드될 때 생성되며 이는 일반적으로 애플리케이션이 시작 시점에 해당된다. 프로퍼티 값은 이 인스턴스에 주입될 때 읽힌다. 스프링은 해당 클래스의 필드와 프로퍼티 파일에서 매핑된 프로퍼티 값을 가져와 주입한다. 따라서 프로퍼티를 가져오는 시점은 스프링 애플리케이션이 시작되고 해당 빈이 생성되고 주입될 때 이다.
따라서 유효성 검사도 이 시점에 진행되는데 만약 필드가 유효성 검사를 통과하지 못하면, 스프링은 애플리케이션 시작 시점에서 예외를 발생시킨다. (애플리케이션을 시작하는 과정에서 발생하므로 런타임 예외)
@ConfigurationProperties
에서 발생한 예외는 애플리케이션 실행을 중지시키는 런타임 예외로, 이 예외는 주로 애플리케이션의 초기화 과정에서 필수적인 설정값을 로드하고 검증하는데 사용된다.