javaspringspring-bootspring-cloudspring-boot-actuator

@RefreshScope beans are recreated, but property used from application.properties is not refreshed


I have a project in which I want to update property from application.properties in runtime, and to recreate the beans that depend on configuration and configuration bean itself with the new/updated value. Beans are destroyed when i call http://localhost:8888/actuator/refresh but the value is not updated. The steps i do :

  1. I call the http://localhost:8888/api/message to verify current value of property.
  2. I edit the application.properties file.
  3. I call http://localhost:8888/actuator/refresh.
  4. I call again /api/message but the value is not updated. And in logs when @PreDestroy is called I also see the the old value.

I have tried also with @Value annotation, but no success and can't figure out the problem.

Any help would be appreciated :)

Below is the code : 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>


Solution

  • It looks like you are changing the wrong application.properties that your application is using. When you build a project with Maven, your resources and compiled classes are placed in the target folder. This is the folder where the application.properties you need to change is located. If you are building the project into an executable jar file, the application.properties will be inside this file, and you will not be able to change it. In this case, just create a new application.properties file next to your jar file and put the desired properties with new values ​​in it. The settings from the external file will override the settings from the internal one, and you will be able to easily change them.

    For more information, see the Externalized Configuration section of the Spring Boot documentation.