How can I refresh Spring configuration file without restarting my servlet container?
I am looking for a solution other than JRebel.
Well, it can be useful to perform such a context reload while testing your app.
You can try the refresh
method of one of the AbstractRefreshableApplicationContext
class: it won't refresh your previously instanciated beans, but next call on the context will return refreshed beans.
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class ReloadSpringContext {
final static String header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\"\n" +
" \t\"http://www.springframework.org/dtd/spring-beans.dtd\">\n";
final static String contextA =
"<beans><bean id=\"test\" class=\"java.lang.String\">\n" +
"\t\t<constructor-arg value=\"fromContextA\"/>\n" +
"</bean></beans>";
final static String contextB =
"<beans><bean id=\"test\" class=\"java.lang.String\">\n" +
"\t\t<constructor-arg value=\"fromContextB\"/>\n" +
"</bean></beans>";
public static void main(String[] args) throws IOException {
//create a single context file
final File contextFile = File.createTempFile("testSpringContext", ".xml");
//write the first context into it
FileUtils.writeStringToFile(contextFile, header + contextA);
//create a spring context
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
new String[]{contextFile.getPath()}
);
//echo the bean 'test' on stdout
System.out.println(context.getBean("test"));
//write the second context into it
FileUtils.writeStringToFile(contextFile, header + contextB);
//refresh the context
context.refresh();
//echo the bean 'test' on stdout
System.out.println(context.getBean("test"));
}
}
And you get this result
fromContextA
fromContextB
Another way to achieve this (and maybe a more simple one) is to use the Refreshable Bean feature of Spring 2.5+ With dynamic language (groovy, etc) and spring you can even change your bean behavior. Have a look to the spring reference for dynamic language:
24.3.1.2. Refreshable beans
One of the (if not the) most compelling value adds of the dynamic language support in Spring is the 'refreshable bean' feature.
A refreshable bean is a dynamic-language-backed bean that with a small amount of configuration, a dynamic-language-backed bean can monitor changes in its underlying source file resource, and then reload itself when the dynamic language source file is changed (for example when a developer edits and saves changes to the file on the filesystem).
I wouldn't recommend you to do that. What do you expect to happen to singleton beans which their configuration modified? do you expect all singletons to reload? but some objects may hold references to that singletons.
See this post as well Automatic configuration reinitialization in Spring
For those stumbling on this more recently -- the current and modern way to solve this problem is to use Spring Boot's Cloud Config.
Just add the @RefreshScope annotation on your refreshable beans and @EnableConfigServer on your main/configuration.
So, for example, this Controller class:
@RefreshScope
@RestController
class MessageRestController {
@Value("${message}")
private String message;
@RequestMapping("/message")
String getMessage() {
return this.message;
}
}
Will return the new value of your message
String property for the /message
endpoint when refresh
is invoked on Spring Boot Actuator (via HTTP endpoint or JMX).
See the official Spring Guide for Centralized Configuration example for more implementation details.
You can take a look at this http://www.wuenschenswert.net/wunschdenken/archives/138 where once you change any thing in the properties file and save it the beans will be reloaded with the new values.