spring / / 2022. 12. 23. 07:44

spring cloud config refresh 적용

spring cloud config를 사용하는 경우 config 설정이 변경될 때 적용하는 방법에 대한 설명이다.

1. Spring Boot Application Properties

Spring application은 파일 혹은 config server에서 propertes를 읽어 들인다.

Spring Boot Application Properties

2. refreshing properties

스프링 컨텍스트에서 properties를 갱신할 때 2가지 단계가 있다. Environment에서 property source를 reloading하는 것과 Spring beans의 속성을 refreshing하는 것.

Spring Cloud Config Server를 사용하는 경우에 Spring Cloud는 config client에서 property를 refresh하기 위해 다음과 같은 방법을 제공한다.

  • Spring Actuator를 사용해서 config client에 있는 /actuator/refresh를 호출한다.
  • Spring Cloud Bus와 연결되어 있는 config client의 /actuator/busrefresh를 호출한다.
  • Spring Cloud Bus와 연결되어 있는 config server의 /monitor를 호출한다.

3. /actuator/refresh 호출

  1. git repository의 변경내용을 commit하고 application에 적용하고자 한다.
    혹은 config server의 application.yml파일을 직접 변경한다. (intellij에서 변경할 때는 src가 아닌 target에 있는 application.yml에서 변경해야 한다)

  2. client application에 노출된 /actuator/refresh를 호출

    curl -H "Content-Type: application/json" -d {} http://localhost:8080/actuator/refresh
  3. 이렇게 호출함으로써, config client는 최근 변경정보를 가져오기 위해서 config server를 호출한다.

  4. 최근 properties정보로, property정보는 갱신이 되고 해당 Bean이 @RefreshScope이 있다면 bean 속성이 갱신된다.

  5. 그런 후에 EnvironmentChangeEvent의 이벤트가 호출되고 변경이 되었는지 확인할 수 있다.

3.1 actuator 의존성 추가

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

3.2 actuator 설정

management:
  endpoints:
    web:
      exposure:
        include: refresh

3.3 @RefreshScope

/actuator/refresh를 호출하여 갱신한 후에 @RefreshScope 어노테이션을 가진 bean에서 @Value를 가진 속성이 갱신된다.
@ConfigurationProperties로 구성된 곳에는 @RefreshScope이 필요하지 않다.

3.4 EnvironmentChangeEvent

@Component
@RefreshScope
public class MyRefreshListener implements ApplicationListener<EnvironmentChangeEvent> {

    @Value("${app.version}")
    public String version;

    @Override
    public void onApplicationEvent(EnvironmentChangeEvent environmentChangeEvent) {
        System.err.println("onApplicationEvent: " + environmentChangeEvent);
        System.err.println("version: " + version);
    }
}

/refresh 호출은 간단하지만 많은 서비스가 있다면 번거로운 일이 될 수 있다.
그래서 bash 스크립트로 configuration이 변경되었을 때 호출해주는 방법이 있을 수도 있다.
하지만 다른 좋은 방법이 있는데 Spring Cloud Bus를 통해 refresh하는 것이다.

4. Spring cloud bus를 통한 refresh

Refresh Process Using Spring Cloud Bus

4.1 의존성 추가

Cloud bus를 사용하려면 Kafka, rabbitmq 같은 메시징 큐가 필요하다. 여기서는 kafka를 통한 업데이트를 할 것이다.

config-server와 config-client에 모두 의존성 추가

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-kafka</artifactId>
    <version>3.1.2</version>
</dependency>

4.2 application.yml 설정 추가

config-server와 config-client의 application.yml에 설정 추가

spring:
  kafka:
    bootstrap-servers:
      localhost:9092 # kafka 서버 주소:포트
  cloud:
    bus:
      enabled: true # 기본값: true

config-client에 busrefresh 추가

management:
  endpoints:
    web:
      exposure:
        include: refresh, busrefresh

4.3 @RefreshScope

busrefresh로 업데이트 되는 경우도 Bean에 @RefreshScope가 있어야 한다.

application.yml에 아래 설정이 있다고 가정

app.version: 1.0

controller를 생성

@RefreshScope
@RestController
public class VersionController {

    @Value("${app.version}")
    public String version;

    @RequestMapping("version")
    public String getVersion() {
        return version;
    }
}

Config server의 target폴더 하위에 값을 2.0으로 변경해보자.

그리고 설정정보 반영을 위해 아래 api를 호출해보자.

POST http://localhost:8080/actuator/busrefresh
content-Type: application/json

다시 조회해보면

GET http://localhost:8080/version

실행결과는 2.0으로 변경되는 것을 확인할 수 있다.

스프링 부트와 스프링 클라우드에서의 Dynamic Configuration Properties

TL;DR

  • @ConfigurationProperties를 사용하고 항상 Bean의 상태를 가진다.
  • Environment는 런타임에 변경될 수 있고 스프링 클라우드는 RefreshEvent를 사용한다.
  • 변경 정보는 스프링 클라우드에서 두 가지 방식으로 전파된다.
    • @ConfigurationProperties, @RefreshScope
  • 동시 접근 시 일관된 상태가 필요하면 @ConfigurationProperties를 사용하고 그렇지 않으면 @RefreshScope를 가진 빈을 사용하면 된다.

@RefreshScope

  • @RefreshScope이 있는 Bean은 프록시로 생성이 된다.
  • 실제 Bean은 시작시점에 생성이 되고 동일한 빈 이름을 가진 키로 캐쉬에 저장된다.
  • 메소드가 프록시를 호출할 때 대상 빈으로 전파된다.
  • EnvironmentChangeEvent가 발생하면 캐쉬는 초기화되고 BeanFactory 콜백이 스프링에서 호출된다. 그리고 나서 다음 메소드 호출 시 재생성된다.

@ConfigurationProperties와 @RefreshScope의 차이

  • @ConfigurationProperties
    • /refresh될 때 항상 Bean이 재생성된다. (destroy -> construct)
  • @RefreshScope
    • @RefreshScope이 붙은 Bean은 프록시(proxy)로 생성이 되고 실제 Bean을 캐쉬에 저장을 한다.
    • /refresh될 때 Proxy의 Bean이 destroy되고 캐쉬의 값이 초기화된다. 그리고 해당 컴포넌트가 실제로 호출될 때 생성(construct)된다.

만일 @ConfigurationProperties@RefreshScope을 붙이면 @RefreshScope붙은 Bean과 같은 동작을 함.

참고

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유