Reloading/Refreshing Spring configuration file without restarting the servlet container

后端 未结 4 1124
轮回少年
轮回少年 2020-11-30 04:43

How can I refresh Spring configuration file without restarting my servlet container?

I am looking for a solution other than JRebel.

相关标签:
4条回答
  • 2020-11-30 05:15

    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).

    0 讨论(0)
  • 2020-11-30 05:15

    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

    0 讨论(0)
  • 2020-11-30 05:21

    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.

    0 讨论(0)
  • 2020-11-30 05:23

    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.

    0 讨论(0)
提交回复
热议问题