업무: Repository 구현체 중에 어떤 구현체를 Bean으로 등록할지 Java 코드의 변경 없이 application.yaml 설정 값을 통해 제어해보세요.
- discodeit.repository.type 설정값에 따라 Repository 구현체가 정해집니다.
- 값이 jcf 이거나 없으면 JCF*Repository 구현체가 Bean으로 등록되어야 합니다.
- 값이 file 이면 File*Repository 구현체가 Bean으로 등록되어야 합니다.
application.yml - 설정 파일
spring:
application:
name: discodeit
discodeit:
repository:
# jcf | file
type: file
file-directory: .discodeit
extension: .ser
먼저 yml에 구현체 선택 설정정보를 추가해줬다.
이 파일에서 type을 쉽게 jcf나 file로 변경을 해주면 자동으로 그에 맞는 repository 구현체를 쓰게 하는 것이 목표다.
RepositorySettings.java - @ConfigurationProperties 클래스
@ConfigurationProperties("discodeit.repository")
// need getters and setters for spring to inject values
@Getter
@Setter
public class RepositorySettings {
// default values unless stated otherwise
private String type = "jcf";
private String fileDirectory = ".discodeit";
private String extension = ".ser";
}
먼저 @ConfigurationProperties를 통해 설정 프러퍼티 클래스를 하나 만들어줬다.
- @ConfigurationProperties
- application.yml 파일의 discodeit.repository 하위 프로퍼티 값들을 RepositorySettings 클래스의 필드(type, fileDirectory, extension) 에 자동으로 바인딩(연결)해주는 역할을 한다.
- @ConfigurationProperties에 대한건 나중에 블로그 포스팅으로 더 자세히 따로 정리할 생각이다.
- Getter와 Setter
- Setter
- 주입(Injection) - 스프링이 application.yml 파일의 값을 RepositorySettings 객체의 필드에 자동으로 넣어주기 위해 필요하다
- @EnableConfigurationProperties(RepositorySettings.class) 때문에 스프링 부트가 시작되면 RepositorySettings 클래스의 비어있는 객체를 만들고, setter들을 이용해서 application.yml에 있는 값들을 파라미터로 넘겨주고 필드에 저장한다.
- Getter
- 다른 곳에서 그 값을 읽어가기 위해 필요하다. 예를 들면 심화 2에 나오는데, 위에 보이는 나머지 두개의 값 (fileDirectory, extension)은 File*Repository 구현체에서 읽혀서 사용된다. File*Repository 구현체로 넘어갈 때 생성자에는 RepositorySettings를 넣어준다.
- Setter
DiscodeitApplication.java (메인 파일)
@SpringBootApplication
@EnableConfigurationProperties(RepositorySettings.class)
public class DiscodeitApplication {
public static void main(String[] args) {
- @EnableConfigurationProperties
- 아까 본 RepositorySettings 클래스에 @Component를 안붙혀줘도 이 어노테이션을 넣으면, 스프링 부트에게 RepositorySettings 클래스를 프로퍼티 바인딩 기능으로 활성화하고 다른 빈에서 주입하여 사용할 수 있도록 만들어달라고 요청하는 것이다.
- 그러면 RepositorySettings 클래스는 빈은 아니지만 스프링 컨테이너가 관리하는 특별한 객체가 된다 -> @Component 계열의 어노테이션이 없어 일반적인 빈(Bean)은 아니지만, @EnableConfigurationProperties를 통해 빈처럼 스프링 컨테이너에 등록되고 다른 곳에 주입될 수 있는 자격을 얻게 된다.
@SpringBootApplication
@ConfigurationPropertiesScan
public class DiscodeitApplication {
public static void main(String[] args) {
참고로 @EnableConfigurationProperties대신 @ConfigurationPropertiesScan을 사용할 수 있다.
@Configuration 클래스 생성 - FileRepositoryConfig, JCFRepositoryConfig
@Configuration이 들어간 클래스 생성을 했다.
- @ConfigurationProperties를 사용한 프로퍼티 클래스 (위에 만든RepositorySettings 클래스)를 통해 빈을 주입한다
@Configuration
@ConditionalOnProperty(
prefix = "discodeit.repository",
name="type",
havingValue = "jcf",
matchIfMissing = true // 디폴트값 설정
)
public class JCFRepositoryConfig {
@Bean
public BinaryContentRepository binaryContentRepository() {
return new JCFBinaryContentRepository();
}
...
@Configuration
@ConditionalOnProperty(
prefix = "discodeit.repository",
name="type",
havingValue = "file"
)
public class FileRepositoryConfig {
@Bean
public BinaryContentRepository binaryContentRepository(RepositorySettings settings) {
return new FileBinaryContentRepository(settings);
}
...
@ConditionalOnProperty
- application.yml에서 두가지 버젼을 (jcf/file)을 고를 수 있는게 목표였기 때문에, @ConditionalOnProperty를 이용해서 두가지 클래스를 만들었다.
- ConditionalOnProperty 어노테이션은 두 클래스 중 하나만 조건에 따라 빈으로 등록된다.
- 어노테이션 설명
- prefix - 경로 (discodeit.repository)
- name - 키 값 (type)
- havingValue - discodeit.repository.type 프로퍼티의 값이 jcf/file이어야 함
- JCFRepositoryConfig
- matchIfMissing = true: 만약 discodeit.repository.type 프로퍼티가 application.yml에 아예 존재하지 않으면, 이 조건을 true로 간주하여 디폴트로 JCFRepositoryConfig를 빈으로 등록한다
- 주어진 조건이 충족되면, 해당 @Configuration 클래스가 활성화되고, 그 안에 있는 @Bean 어노테이션이 붙은 메소드들이 실행된다.
- 스프링이 @Bean을 등록할 때, 파라미터로 필요한 객체(여기서는 RepositorySettings)가 이미 컨테이너에 의해 관리되고 있다면 자동으로 주입(DI)해준다.
- 어노테이션 설명
결과


간단하게 getBean을 사용해서 결과를 프린트해보면 잘 나오고, 테스트 케이스도 모두 통과한다.
'Codeit > 스프린트 과제' 카테고리의 다른 글
| [sprint8] S3 관련 코드 + S3Client와 Presigned Url (3) | 2025.08.25 |
|---|---|
| [sprint8] 어플리케이션 컨테이너화 - dockerfile, docker compose, docker volume (1) | 2025.08.22 |
| [sprint5] 과제에서 사용한 swagger 간단하게 정리 (0) | 2025.07.14 |
| [sprint4] IOException과 @Transactional (멘토님 피드백) (0) | 2025.07.14 |
| [sprint3] 심화 2 - application.yaml로 Bean 구현하기 (File*Repository 구현체의 파일 저장 경로 설정하기 (2) | 2025.06.28 |