애너테이션을 사용하지 않고 PropertySource 등록하기

작성일: 2021-10-18 23:24

사용자 정의 PropertySource를 등록할 때 @PropertySource를 사용하면 쉽게 등록이 가능하지만 다른 설정 값들을 기반으로 Property 파일을 유연하게 변경하기 어렵다.

Property 파일을 유연하게 변경하기 위해 java code 기반으로 PropertySource를 알아보려고 한다.

# 방법 1.ApplicationContextInitializer

ApplicationContextInitializer를 통해 PropertySource를 추가할 수 있다.

public class PropertySourceConfigurer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        try {
            MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
            Resource resource = new ClassPathResource(resourcePath());
            propertySources.addLast(new ResourcePropertySource(resource));
        } catch (Exception e) {
            throw new IllegalStateException("Failed to add property source", e);
        }
    }

    private String resourcePath() {
        // some logic...
        return "test.properties";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

스프링 부트 프로젝트라면 아래와 같이 Initizlizer를 추가할 수 있다.

public static void main(String[] args) {
        new SpringApplicationBuilder(JavaSpringConfigurationApplication.class)
                .initializers(new PropertySourceConfigurer())
                .run(args);
    }
1
2
3
4
5

# 방법 2.EnvironmentPostProcessor(Spring Boot only)

스프링 부트에서는 스프링 부트 자체적으로 제공하는 EnvironmentPostProcessor를 통해 PropertySource를 추가할 수 있다.

public class PropertySourceConfigurer implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        try {
            MutablePropertySources propertySources = environment.getPropertySources();
            Resource resource = new ClassPathResource(resourcePath());
            propertySources.addLast(new ResourcePropertySource(resource));
        } catch (Exception e) {
            throw new IllegalStateException("Failed to add property source", e);
        }
    }

    private String resourcePath() {
        // some logic...
        return "test.properties";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

EnvironmentPostProcessor는 ApplicationContext 생성 전 Environment를 생성하는 시점에 실행된다.

그러므로 스프링 빈 등록이 아닌 META-INF/spring.factories에 등록이 필요하다.

// resources/META-INF/spring.factories
org.springframework.boot.env.EnvironmentPostProcessor=com.example.demo.PropertySourceConfigurer
1
2

# 방법 3.BeanFactoryPostProcessor

빈 초기화 전 한번만 수행되는 BeanFactoryPostProcessor를 통해 PropertySource를 추가할 수 있다.

@PropertySource 또한 BeanFactoryPostProcessor를 확장한 BeanDefinitionRegistryPostProcessor 구현체인 ConfigurationClassPostProcessor에서 추가된다.

@Component
public class PropertySourceConfigurer implements BeanFactoryPostProcessor, EnvironmentAware {

    private Environment environment;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if (environment instanceof ConfigurableEnvironment) {
            try {
                MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
                Resource resource = new ClassPathResource(resourcePath());
                propertySources.addLast(new ResourcePropertySource(resource));
            } catch (Exception e) {
                throw new IllegalStateException("Failed to add property source", e);
            }
        }
    }

    private String resourcePath() {
        // some logic...
        return "test.properties";
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

BeanFactoryPostProcessor는 ApplicationContext가 refresh될 때 수행되므로 빈 등록이 필요하다. 추가로 Environment를 사용하기 위해 EnvironmentAware 구현이 필요하다.