1. 개요
이 예제에서는 Spring 애플리케이션에서 속성 을 다시로드하는 방법을 보여줄 것 입니다.
2. Spring에서 속성 읽기
Spring에서 속성에 액세스하는 다른 옵션이 있습니다.
- 환경 - 우리는 삽입 할 수 환경을 다음 사용 환경 # getProperty에를 주어진 속성을 읽을 수 있습니다. 환경 에는 시스템 속성, -D 매개 변수 및 application.properties (.yml) 와 같은 다양한 속성 소스가 포함 됩니다. 또한 @PropertySource를 사용하여 추가 속성 소스를 환경에 추가 할 수 있습니다 .
- 속성 — 속성 파일을 Properties 인스턴스 로로드 한 다음 properties.get ( "property")를 호출하여 빈에서 사용할 수 있습니다.
- @Value — @Value ($ { 'property'}) 어노테이션을 사용하여 빈에 특정 속성을 삽입 할 수 있습니다.
- @ConfigurationProperties — @ConfigurationProperties 를사용하여 빈에 계층 적 속성을로드할 수 있습니다.
3. 외부 파일에서 속성 다시로드
런타임 중에 파일의 속성을 변경하려면 해당 파일을 jar 외부에 배치해야합니다. 그런 다음 명령 줄 매개 변수 –spring.config.location = file : // {path to file}을 사용하여 Spring이 어디에 있는지 알려줍니다 . 또는 application.properties에 넣을 수 있습니다 .
파일 기반 속성에서 파일을 다시로드하는 방법을 선택해야합니다. 예를 들어 엔드 포인트 또는 스케줄러를 개발하여 파일을 읽고 속성을 업데이트 할 수 있습니다.
파일을 다시로드하기위한 편리한 라이브러리 중 하나는 Apache의 commons-configuration 입니다. 다른 ReloadingStrategy 와 함께 PropertiesConfiguration 을 사용할 수 있습니다 .
pom.xml에 commons-configuration 을 추가해 보겠습니다 .
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>
그런 다음 나중에 사용할 PropertiesConfiguration 빈 을 만드는 메서드를 추가합니다 .
@Bean
@ConditionalOnProperty(name = "spring.config.location", matchIfMissing = false)
public PropertiesConfiguration propertiesConfiguration(
@Value("${spring.config.location}") String path) throws Exception {
String filePath = new File(path.substring("file:".length())).getCanonicalPath();
PropertiesConfiguration configuration = new PropertiesConfiguration(
new File(filePath));
configuration.setReloadingStrategy(new FileChangedReloadingStrategy());
return configuration;
}
위의 코드에서는 기본 새로 고침 지연이있는 다시로드 전략으로 FileChangedReloadingStrategy 를 설정했습니다 . 즉, PropertiesConfiguration 은 마지막 확인이 5000ms 이전 인 경우 파일 수정 날짜를 확인 합니다.
FileChangedReloadingStrategy # setRefreshDelay를 사용하여 지연을 사용자 지정할 수 있습니다 .
3.1. 환경 속성 다시로드
Environment 인스턴스를 통해로드 된 속성을 다시로드 하려면 PropertySource 를 확장 한 다음 PropertiesConfiguration 을 사용 하여 외부 속성 파일에서 새 값을 반환해야합니다 .
PropertySource 확장부터 시작하겠습니다 .
public class ReloadablePropertySource extends PropertySource {
PropertiesConfiguration propertiesConfiguration;
public ReloadablePropertySource(String name, PropertiesConfiguration propertiesConfiguration) {
super(name);
this.propertiesConfiguration = propertiesConfiguration;
}
public ReloadablePropertySource(String name, String path) {
super(StringUtils.hasText(name) ? path : name);
try {
this.propertiesConfiguration = new PropertiesConfiguration(path);
this.propertiesConfiguration.setReloadingStrategy(new FileChangedReloadingStrategy());
} catch (Exception e) {
throw new PropertiesException(e);
}
}
@Override
public Object getProperty(String s) {
return propertiesConfiguration.getProperty(s);
}
}
getProperty 메서드를 재정 의하여 PropertiesConfiguration # getProperty 에 위임했습니다 . 따라서 새로 고침 지연에 따라 간격으로 업데이트 된 값을 확인합니다.
이제 ReloadablePropertySource 를 Environment 의 속성 소스 에 추가 할 것입니다.
@Configuration
public class ReloadablePropertySourceConfig {
private ConfigurableEnvironment env;
public ReloadablePropertySourceConfig(@Autowired ConfigurableEnvironment env) {
this.env = env;
}
@Bean
@ConditionalOnProperty(name = "spring.config.location", matchIfMissing = false)
public ReloadablePropertySource reloadablePropertySource(PropertiesConfiguration properties) {
ReloadablePropertySource ret = new ReloadablePropertySource("dynamic", properties);
MutablePropertySources sources = env.getPropertySources();
sources.addFirst(ret);
return ret;
}
}
동일한 키로 기존 속성을 재정의하기 위해 새 속성 소스를 첫 번째 항목으로 추가했습니다 .
Environment 에서 속성을 읽는 빈을 만들어 보겠습니다 .
@Component
public class EnvironmentConfigBean {
private Environment environment;
public EnvironmentConfigBean(@Autowired Environment environment) {
this.environment = environment;
}
public String getColor() {
return environment.getProperty("application.theme.color");
}
}
다시로드 할 수있는 다른 외부 속성 소스를 추가해야하는 경우 먼저 사용자 정의 PropertySourceFactory 를 구현해야합니다 .
public class ReloadablePropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String s, EncodedResource encodedResource)
throws IOException {
Resource internal = encodedResource.getResource();
if (internal instanceof FileSystemResource)
return new ReloadablePropertySource(s, ((FileSystemResource) internal)
.getPath());
if (internal instanceof FileUrlResource)
return new ReloadablePropertySource(s, ((FileUrlResource) internal)
.getURL()
.getPath());
return super.createPropertySource(s, encodedResource);
}
}
그런 다음 @PropertySource 로 구성 요소의 클래스에 어노테이션을 달 수 있습니다 .
@PropertySource(value = "file:path-to-config", factory = ReloadablePropertySourceFactory.class)
3.2. 속성 인스턴스 다시로드
특히 파일에서 속성을 다시로드해야 할 때 환경 이 Properties 보다 더 나은 선택 입니다. 그러나 필요한 경우 java.util.Properties를 확장 할 수 있습니다 .
public class ReloadableProperties extends Properties {
private PropertiesConfiguration propertiesConfiguration;
public ReloadableProperties(PropertiesConfiguration propertiesConfiguration) throws IOException {
super.load(new FileReader(propertiesConfiguration.getFile()));
this.propertiesConfiguration = propertiesConfiguration;
}
@Override
public String getProperty(String key) {
String val = propertiesConfiguration.getString(key);
super.setProperty(key, val);
return val;
}
// other overrides
}
getProperty 및 해당 오버로드를 재정의 한 다음이를 PropertiesConfiguration 인스턴스에 위임했습니다 . 이제이 클래스의 빈을 생성하여 컴포넌트에 삽입 할 수 있습니다.
3.3. @ConfigurationProperties로 Bean 다시로드
@ConfigurationProperties로 동일한 효과를 얻으려면 인스턴스를 재구성해야합니다.
그러나 Spring은 프로토 타입 또는 요청 범위가 있는 새 구성 요소 인스턴스 만 생성합니다 .
따라서 환경을 다시로드하는 우리의 기술도 작동하지만 싱글 톤의 경우 엔드 포인트를 구현하여 Bean을 파괴하고 다시 생성하거나 Bean 자체 내에서 속성 다시로드를 처리하는 것 외에는 선택의 여지가 없습니다.
3.4. @Value로 Bean 다시로드
@Value 어노테이션과 같은 제한 제시 @ConfigurationProperties을 .
4. 액추에이터 및 클라우드로 속성 다시로드
Spring Actuator 는 상태, 메트릭 및 구성에 대해 서로 다른 엔드 포인트를 제공하지만 Bean 새로 고침에는 아무것도 제공하지 않습니다. 따라서 / refresh 엔드 포인트를 추가하려면 Spring Cloud가 필요 합니다. 이 엔드 포인트는 모든 재산 소스 다시로드 환경을 한 다음 발행 EnvironmentChangeEvent을 .
Spring Cloud는 또한 @RefreshScope 를 도입 했으며 이를 구성 클래스 또는 빈에 사용할 수 있습니다. 결과적으로 기본 범위는 singleton 대신 새로 고침 됩니다 .
새로 고침 범위를 사용하여 Spring은 EnvironmentChangeEvent 에서 이러한 구성 요소의 내부 캐시를 지 웁니다 . 그런 다음 Bean에 대한 다음 액세스시 새 인스턴스가 작성됩니다.
spring-boot-starter-actuator 를 pom.xml 에 추가하는 것으로 시작하겠습니다 .
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
그런 다음 spring-cloud-dependencies 도 가져옵니다 .
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
그런 다음 spring-cloud-starter를 추가합니다 .
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
마지막으로 새로 고침 끝점을 활성화하겠습니다.
management.endpoints.web.exposure.include=refresh
Spring Cloud를 사용할 때 속성을 관리 하기 위해 Config Server 를 설정할 수 있지만 외부 파일도 계속 사용할 수 있습니다. 이제 속성을 읽는 두 가지 다른 메서드 인 @Value 및 @ConfigurationProperties를 처리 할 수 있습니다 .
4.1. @ConfigurationProperties로 Bean 새로 고침
@RefreshScope 와 함께 @ConfigurationProperties 를 사용하는 방법을 보여 드리겠습니다 .
@Component
@ConfigurationProperties(prefix = "application.theme")
@RefreshScope
public class ConfigurationPropertiesRefreshConfigBean {
private String color;
public void setColor(String color) {
this.color = color;
}
//getter and other stuffs
}
우리 bean은 루트 “application 에서 “ color” 속성을 읽고 있습니다. 테마” 속성 . Spring 문서에 따라 setter 메서드가 필요합니다.
외부 구성 파일에서 “ application.theme.color ” 값을 변경 한 후 / refresh를 호출 할 수 있으므로 다음에 액세스 할 때 빈에서 새 값을 가져올 수 있습니다.
4.2. @Value로 빈 새로 고침
샘플 구성 요소를 만들어 보겠습니다.
@Component
@RefreshScope
public class ValueRefreshConfigBean {
private String color;
public ValueRefreshConfigBean(@Value("${application.theme.color}") String color) {
this.color = color;
}
//put getter here
}
새로 고침 과정은 위와 동일합니다.
그러나 / refresh 는 명시적인 싱글 톤 범위를 가진 빈에서는 작동하지 않는다는 점에 유의해야합니다 .
5. 결론
이 예제에서는 Spring Cloud 기능을 사용하거나 사용하지 않고 속성을 다시로드하는 방법을 보여주었습니다. 또한 각 기술의 함정과 예외를 보여주었습니다.
전체 코드는 GitHub 프로젝트에서 사용할 수 있습니다 .
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/spring-reloading-properties
'Java' 카테고리의 다른 글
RAML 소개 – RESTful API 모델링 언어 (0) | 2021.04.21 |
---|---|
Redis 대 MongoDB (0) | 2021.04.21 |
Spring Boot : Jackson ObjectMapper 사용자 지정 (0) | 2021.04.20 |
Spring DispatcherServlet 소개 (0) | 2021.04.20 |
Spring MVC의 ViewResolver 사용방법(예제) (0) | 2021.04.20 |