@Bean с аннотацией @RefreshScope пересоздаются, но свойство, используемое из application.properties, не обновляется.

Вопрос или проблема

У меня есть проект, в котором я хочу обновлять свойства из application.properties во время выполнения и пересоздавать бины, которые зависят от конфигурации, и сам конфигурационный бин с новым/обновленным значением. Бины уничтожаются, когда я вызываю http://localhost:8888/actuator/refresh, но значение не обновляется. Шаги, которые я выполняю:

  1. Я вызываю http://localhost:8888/api/message, чтобы проверить текущее значение свойства.
  2. Я редактирую файл application.properties.
  3. Я вызываю http://localhost:8888/actuator/refresh.
  4. Я снова вызываю /api/message, но значение не обновляется. И в логах, когда вызывается @PreDestroy, я также вижу старое значение.

Я также пробовал использовать аннотацию @Value, но безуспешно и не могу понять, в чем проблема.

Буду признателен за любую помощь 🙂

Ниже приведен код:
ConfigProperties.java

package org.example.refreshscopeworkingproject;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "demo")
@RefreshScope
public class ConfigProperties {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    @PostConstruct
    public void init() {
        System.out.println("ConfigProperties bean created with message: " + message);
    }
    @PreDestroy
    public void destroy() {
        System.out.println("ConfigProperties destroyed");
    }
}

DemoController.java

package org.example.refreshscopeworkingproject;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
@RefreshScope
public class DemoController {
    private final ConfigProperties configProperties;

    public DemoController(ConfigProperties configProperties) {
        this.configProperties = configProperties;
    }

    @GetMapping("/message")
    public String getMessage() {
        return configProperties.getMessage();
    }

    @PostConstruct
    public void init() {
        System.out.println("Controller initialized");
    }
    @PreDestroy
    public void destroy() {
        System.out.println("Controller destroyed");
    }
}

RefreshScopeWorkingProjectApplication.java

package org.example.refreshscopeworkingproject;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RefreshScopeWorkingProjectApplication {

    public static void main(String[] args) {
        SpringApplication.run(RefreshScopeWorkingProjectApplication.class, args);
    }

}

application.properties :

demo.message=Hello, RefreshScope1111!
management.endpoints.web.exposure.include=*
logging.level.org.springframework.boot.actuate=DEBUG
logging.level.org.springframework.boot.context.properties=DEBUG
server.port=8888

pom.xml :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>RefreshScopeWorkingProject</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>RefreshScopeWorkingProject</name>
    <description>RefreshScopeWorkingProject</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
            <version>4.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.6.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Ответ или решение

Ваша проблема касается обновления значений свойств из файла application.properties в приложении Spring Boot с использованием аннотации @RefreshScope. На первый взгляд, у вас уже настроено все правильно: классы помечены нужными аннотациями для повторного создания бинов, и вызов эндпоинта /actuator/refresh тоже осуществляется. Однако, давайте разберёмся, почему само значение свойства остается старым.

Возможные причины проблемы:

  1. Отсутствие поддержки изменения файлов на лету:
    Spring Boot по умолчанию не поддерживает автоматическую загрузку измененных локальных файлов свойств. Больше всего обновление свойств эффективно при использовании Spring Cloud Config Server, который внешне управляет конфигурациями и перезагружает их.

  2. Кэширование значений:
    Даже если бин с аннотацией @RefreshScope пересоздаётся, значение свойства может кешироваться на уровне другого элемента вашей системы.

  3. Ошибки при конфигурации @ConfigurationProperties:
    Убедитесь, что все свойства хорошо связаны с префиксом в вашем классе конфигурации. Из-за этого может возникнуть несоответствие при обновлении значений.

Рекомендации по исправлению:

  1. Используйте Spring Cloud Config Server:
    Для полноценного обновления конфигурации через Spring Cloud, стоит рассмотреть возможность использования Spring Cloud Config Server. Он позволяет хранить конфигурационные свойства в репозитории (например, Git), и ваш клиент может получить обновления напрямую от Конфигурационного Сервера.

  2. Убедитесь в корректности префиксов и аннотаций:
    Проверьте, что ваш ConfigProperties класс правильно структурирован, и все префиксы совпадают с вашим application.properties.

  3. Посмотрите на использование других PropertySource:
    Возможно, у вас есть другие источники конфигурации, которые переопределяют местные свойства. Убедитесь, что при загрузке конфигурации не присутствует Парсон настроек, влияющих на это поведение.

  4. Логирование и мониторинг:
    Активируйте вывод дебаг-логов для org.springframework.boot.context.properties, чтобы проверить успешность загрузки обновленных свойств. Это поможет определить, загружаются ли ваши новые значения.

Заключение

Чтобы отладка была более успешной, начните с простого использования @RefreshScope, и далее переходите к более сложным решениям, таким как Spring Cloud Config Server, если ваш проект нуждается в динамическом управлении конфигурацией в более сложной инфраструктуре. Надеюсь, что эти рекомендации помогут вам настроить обновление свойств в вашем приложении.

Оцените материал
Добавить комментарий

Капча загружается...