8

I am using spring boot, and I have two external properties files, so that I can easily change its value.

But I hope spring app will reload the changed value when it is updated, just like reading from files. Since property file is easy enough to meet my need, I hope I don' nessarily need a db or file.

I use two different ways to load property value, code sample will like:

@RestController
public class Prop1Controller{

    @Value("${prop1}")
    private String prop1;


    @RequestMapping(value="/prop1",method = RequestMethod.GET)
    public String getProp() {
        return prop1;
    }
}


@RestController
public class Prop2Controller{

    @Autowired
    private Environment env;

    @RequestMapping(value="/prop2/{sysId}",method = RequestMethod.GET)
    public String prop2(@PathVariable String sysId) {
        return env.getProperty("prop2."+sysId);
    }
}

I will boot my application with

-Dspring.config.location=conf/my.properties
JaskeyLam
  • 15,405
  • 21
  • 114
  • 149

6 Answers6

2

I'm afraid you will need to restart Spring context.

luboskrnac
  • 23,973
  • 10
  • 81
  • 92
1

I think the only way to achieve your need is to enable spring-cloud. There is a refresh endpoint /refresh which refreshes the context and beans.

I'm not quite sure if you need a spring-cloud-config-server (its a microservice and very easy to build) where your config is stored(Git or svn). Or if its also useable just by the application.properties file in the application.

Here you can find the doc to the refresh scope and spring cloud.

Patrick
  • 12,336
  • 15
  • 73
  • 115
1

You should be able to use Spring Cloud for that

Add this as a dependency

compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.2.RELEASE'

And then use @RefreshScope annotation

A Spring @Bean that is marked as @RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.

Also relevant if you have Spring Actuator

For a Spring Boot Actuator application there are some additional management endpoints:

POST to

/env to update the Environment and rebind @ConfigurationProperties and log levels

/refresh for re-loading the boot strap context and refreshing the @RefreshScope beans

Spring Cloud Doc

Janar
  • 2,623
  • 1
  • 22
  • 32
0

(1) Spring Cloud's RestartEndPoint

You may use the RestartEndPoint: Programatically restart Spring Boot application / Refresh Spring Context

RestartEndPoint is an Actuator EndPoint, bundled with spring-cloud-context.

However, RestartEndPoint will not monitor for file changes, you'll have to handle that yourself.


(2) devtools

I don't know if this is for a production application or not. You may hack devtools a little to do what you want.

Take a look at this other answer I wrote for another question: Force enable spring-boot DevTools when running Jar

Devtools monitors for file changes:

Applications that use spring-boot-devtools will automatically restart whenever files on the classpath change.

Technically, devtools is built to only work within an IDE. With the hack, it also works when launched from a jar. However, I may not do that for a real production application, you decide if it fits your needs.

Community
  • 1
  • 1
alexbt
  • 16,415
  • 6
  • 78
  • 87
0

I know this is a old thread, but it will help someone in future.

You can use a scheduler to periodically refresh properties.

//MyApplication.java
@EnableScheduling

//application.properties
management.endpoint.refresh.enabled = true

//ContextRefreshConfig.java
@Autowired
private RefreshEndpoint refreshEndpoint;

@Scheduled(fixedDelay = 60000, initialDelay = 10000)
public Collection<String> refreshContext() {
    final Collection<String> properties = refreshEndpoint.refresh();
    LOGGER.log(Level.INFO, "Refreshed Properties {0}", properties);
    return properties;
}

//add spring-cloud-starter to the pom file.

Attribues annotated with @Value is refreshed if the bean is annotated with @RefreshScope. Configurations annotated with @ConfigurationProperties is refreshed without @RefreshScope. Hope this will help.

Sudheera
  • 355
  • 3
  • 8
-1

You can follow the ContextRefresher.refresh() code implements.

public synchronized Set<String> refresh() {
        Map<String, Object> before = extract(
                this.context.getEnvironment().getPropertySources());
        addConfigFilesToEnvironment();
        Set<String> keys = changes(before,
                extract(this.context.getEnvironment().getPropertySources())).keySet();
        this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
        this.scope.refreshAll();
        return keys;
    }
fisherhe
  • 1
  • 2