Spring cloud custom configuration source and configuration refresh

Spring cloud custom configuration source and configuration refresh

You can access your own configuration service through a custom configuration source, and cooperate with ContextRefresher to automatically update the configuration while the application is running.

Implement PropertySourceLocator

/**
 * Custom configuration source
 */
public class MyPropertySourceLocator implements PropertySourceLocator {

    @Override
    public PropertySource<?> locate(Environment environment) {
        String msg = new SimpleDateFormat("HH:mm:ss").format(new Date());

        Map<String, Object> map = new HashMap<>();
        map.put("demo.diy.msg", msg);
        System.err.println("MyPropertySourceLocator, demo.diy.msg = "+ msg);

       //Spring comes with a simple map structure configuration collection, you can also inherit PropertySource customization
        MapPropertySource source = new MapPropertySource("my-source", map);
        return source;
    }
}

Configuration class

@Configuration
public class MyConfigBootstrapConfiguration {

    @Bean
    public MyPropertySourceLocator myPropertySourceLocator() {
        return new MyPropertySourceLocator();
    }

}

To declare a bean in Java code, it also needs to be declared in resources/META-INF/spring.factories

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.netease.ag.demoweb.MyConfigBootstrapConfiguration

The loading mechanism in Spring is similar to that of Java SPI. It configures the implementation class name of the interface in the META-INF/spring.factories file, and then reads and instantiates these configuration files in the program. This custom SPI mechanism is the basis of Spring Boot Starter's implementation.

Use custom configuration

@RefreshScope//Updateable
@Component
@Data
public class ValueConfig {

    @Value("${demo.copy.msg}")
    private String copyMsg;

    @Value("${demo.diy.msg}")
    private String diyMsg;

    public ValueConfig() {
        System.err.println("ValueConfig init");
    }
}

Custom configuration can be referenced in application.properties

demo.copy.msg=${demo.diy.msg}

springboot application start

@SpringBootApplication
@RestController
public class DemowebApplication {

    @Resource
    private ValueConfig valueConfig;

    @Resource
    private ContextRefresher contextRefresher;

    public DemowebApplication() {
        System.err.println("DemowebApplication init");
    }

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

    @RequestMapping("/t")
    public String t() {
        return valueConfig.toString();
    }

   //Update bean properties
    @RequestMapping("/r")
    public Object r() {
        return contextRefresher.refresh();
    }

Startup log

. ____ _ __ _ _
/\/___'_ __ _ _(_)_ __ __ _///\
(()\___ |'_ |'_| |'_//_` |///\
\\/___)| |_)| | | | | || (_| |))))
  '|____| .__|_| |_|_| |_\__, |////
 ==========|_|==============|___/=/_/_/_/
 :: Spring Boot :: (v1.5.2.RELEASE)

MyPropertySourceLocator, demo.diy.msg = 17:18:22
...
DemowebApplication init
...
ValueConfig init
...Tomcat started on port(s): 8080 (http)

Query, multiple requests return consistent

Request: http://localhost:8080/t Response: ValueConfig(copyMsg=17:18:22, diyMsg=17:18:22)

Update

Request: http://localhost:8080/r Response: ["demo.diy.msg"]

Log output:

MyPropertySourceLocator, demo.diy.msg = 17:27:44

Call the query interface again, find that the value has changed, and output the log

ValueConfig init

Prove that the updated field actually regenerates a bean.