
스프링은 다양한 외부 설정 값을 통합적으로 관리하기 위해 Environment
와 PropertySource
라는 개념을 제공한다.
이를 통해 OS 환경 변수, 자바 시스템 속성, 커맨드 라인 옵션 인수, 그리고 설정 파일 등 다양한 외부 설정 값을 하나의 인터페이스로 관리할 수 있다.
이번 글에서는 스프링의 외부 설정 통합 관리 구조와 동작 원리를 알아보겠다.
1. 스프링의 외부 설정 통합
스프링은 외부 설정을 Environment와 PropertySource를 통해 추상화하여 관리한다.
이를 통해 개발자는 외부 설정 값을 동일한 방법으로 읽을 수 있다.
1.1 Environment 인터페이스 개념
Environment는 스프링에서 설정값을 통합적으로 관리하는 추상화 인터페이스이다.
- 역할: 다양한 외부 설정 값을 키-값 쌍으로 관리하고 제공
- 외부 설정 종류: OS 환경 변수, 자바 시스템 속성, 커맨드 라인 인수, 설정 파일 등
- 주요 메서드:
getProperty(String key)
를 사용해 설정값을 조회
1.2 PropertySource를 통한 설정 조회 추상화
PropertySource
는 Environment가 외부 설정을 관리하기 위해 사용하는 추상화 객체이다.
각 설정 소스(OS 환경 변수, 설정 파일, 시스템 속성 등)는 PropertySource
의 구현체로 관리된다.
2. Environment 사용법
Environment
의 getProperty()
메서드를 사용하면 설정값을 조회할 수 있다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
public class Env {
private final Environment environment;
@Autowired
public EnvExample(Environment environment) {
this.environment = environment;
}
public void printConfig() {
System.out.println("server.port = " + environment.getProperty("server.port"));
System.out.println("db.username = " + environment.getProperty("db.username"));
}
}
getProperty()
메셔드로 모든 외부설정 정보를 읽을 수 있다.Environment
가 위 클래스에서처럼 주입이 될 수 있는 이유는 스프링이 내부적으로 Envirment구현체를 만들어서 빈으로 등록해주기 때문이다.
3. 스프링 컨테이너 초기화 시 Environment 등록 과정
스프링 컨테이너가 초기화될 때 Environment
는 자동으로 생성되고 설정된다. 이 과정은 ApplicationContext
의 refresh()
메서드를 시작으로 생성된다.
3.1 AbstractApplicationContext 추상 클래스
스프링 부트를 사용하든 스프링을 사용하든 거의 모든 애플리케이션의 컨텍스트는 AbstractApplicationContext
를 거친다.
1. refresh()
refresh()
메서드는 스프링 컨테이너를 초기화하는 핵심 메서드이다.
이 과정에서 prepareRefresh()
와 prepareBeanFactory()
가 호출된다.
public void refresh() throws BeansException, IllegalStateException {
this.startupShutdownLock.lock();
try {
this.startupShutdownThread = Thread.currentThread();
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh(); //여기 메서드 안에서 Environment 초기화
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory); // 여기서 Enviroment를 bean으로 등록
...
}
...
}
2. prepareRefresh()
Environment
객체를 생성하고 검증한다.
protected void prepareRefresh() {
this.getEnvironment().validateRequiredProperties();
}
3. prepareBeanFactory()
- 생성된
Environment
를 스프링 빈으로 등록한다.protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { beanFactory.registerSingleton("environment", this.getEnvironment()); }
3.2 StandardEnvironment 클래스
StandardEnvironment
는 스프링에서 제공하는 Environment
인터페이스의 구현체이다.
이 클래스는 OS 환경 변수와 JVM 시스템 속성을 PropertySource로 등록한다.
public class StandardEnvironment extends AbstractEnvironment {
/** System environment property source name: {@value}. */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value}. */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
public StandardEnvironment() {
}
protected StandardEnvironment(MutablePropertySources propertySources) {
super(propertySources);
}
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(
new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(
new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}
3.3 정리
- 처음
AnnotationConfigApplicationContext
로 스프링 컨텍스트를 초기화시키면refresh
메서드가 실행이 된다.refresh
메서드는 부모 클래스인AbstractApplicationContext
안에서 구현되어있고,GenericApplicationContext
의 부모 클래스가AbstractApplicationContext
이다.
스프링 부트는 자동으로context
를 추가하는데 애플리케이션 유형에 따라 다른context
가 주입된다. 하지만Environment
등록하는 기본 로직은 비슷하다. AbstractApplicationContext
클래스의refresh
메서드 안에 있는prepareRefresh
메서드에서Environment
가 초기화 된다.- 정확히는
prepareRefresh
메서드의this.getEnvironment().validateRequiredProperties()
에서 초기화가 되고 검증도 이루어진다. getEnvironment
는 내부적으로createEnvironment
를 실행하고, 그 메서드는StandardEnvironment
클래스를 초기화한다.
즉, 스프링의 defaultEnvironment
는StandardEnvironment
클래스임을 알 수 있다.- 다시
refresh
메서드로 돌아오면prepareBeanFactory
메서드를 호출하는 것을 알 수 있고,Environment
를 bean으로 등록하는 것을 알 수 있다. StandardEnvironment
클래스를 보면 두 개의 필드에 OS환경변수와 JVM환경변수를 처리하려는 걸 알 수 있고,customizePropertySources
메서드에서PropertySource
로 등록한다.PropertiesPropertySource
와SystemEnvironmentPropertySource
는PropertySource
의 구현체이다.StandardEnvironment
의 생성자는 부모 생성자를 호출하고, 부모 클래스AbstractEnvironment
에서customizePropertySources
을 호출하는 것을 알 수 있다.
커맨드 라인 옵션 인수는 스프링부트에서 지원하기 때문에 스프링 레거시에서는 사용할 수 없다.
스프링레거시에서 properties파일은 직접 등록 해야하고, yml에 대한 설정 클래스는 지원해주지만 직접 변환해서 등록해야한다. 반면 스프링 부트는 둘 다 자동 등록해서 지원해준다.
다음 글에서는 스프링 레거시와 스프링 부트에서 외부 설정과 설정 파일(Properties, Yaml)을 어떻게 활용하는지를 알아보겠다.
'Backend > Spring' 카테고리의 다른 글
BeanFactory와 ApplicationContext (0) | 2024.12.28 |
---|---|
서블릿 컨테이너 초기화와 스프링의 처리 방식 (0) | 2024.12.27 |
4부: @ConfigurationProperties으로 타입 안전하게 외부 설정 관리 (0) | 2024.12.23 |
3부: 스프링 레거시와 스프링부트의 외부 설정 (1) | 2024.12.21 |
1부: 자바 애플리케이션에서 외부 설정 조회 방법 (0) | 2024.12.18 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!