通过自定义配置源可以接入自己的配置服务,配合ContextRefresher可以让应用运行中自动更新配置。
实现PropertySourceLocator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | 
 
  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);
                   MapPropertySource source = new MapPropertySource("my-source", map);         return source;     } }
 
  | 
 
配置类
1 2 3 4 5 6 7 8 9
   | @Configuration public class MyConfigBootstrapConfiguration {
      @Bean     public MyPropertySourceLocator myPropertySourceLocator() {         return new MyPropertySourceLocator();     }
  }
   | 
 
用Java代码声明bean,还需要在resources/META-INF/spring.factories中声明
1 2
   | org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.netease.ag.demoweb.MyConfigBootstrapConfiguration
   | 
 
Spring中类似与Java SPI的加载机制。它在META-INF/spring.factories文件中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。这种自定义的SPI机制是Spring Boot Starter实现的基础。
使用自定义配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | @RefreshScope  @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");     } }
   | 
 
application.properties中可以引用自定义配置
1
   | demo.copy.msg=${demo.diy.msg}
  | 
 
springboot应用启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | @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();     }
           @RequestMapping("/r")     public Object r() {         return contextRefresher.refresh();     }
   | 
 
启动日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   |   .   ____          _            __ _ _  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )   '  |____| .__|_| |_|_| |_\__, | / / / /  =========|_|==============|___/=/_/_/_/  :: Spring Boot ::        (v1.5.2.RELEASE)
  MyPropertySourceLocator, demo.diy.msg = 17:18:22 ... DemowebApplication init ... ValueConfig init ...Tomcat started on port(s): 8080 (http)
   | 
查询,多次请求返回一致
请求:http://localhost:8080/t
响应:ValueConfig(copyMsg=17:18:22, diyMsg=17:18:22)
更新
请求:http://localhost:8080/r
响应:[“demo.diy.msg”]
日志输出:
1
   | MyPropertySourceLocator, demo.diy.msg = 17:27:44
   | 
再次调用查询接口,发现值改变,并且输出日志
证明更新字段实际是重新生成了一个bean