springboot-監聽apollo配置
一、從apollo讀取配置:包括apollo本地搭建和從apollo讀取配置的基本方法
二、監聽apollo配置
1.1、目的:當我們把一些配置放在apollo中,但是裡面有一些可變的配置,由於要測試,或者需求更改,或者其它問題,apollo有的配置總之會修改,如果不加監聽apollo配置的方法,我們每次修改配置之後都需要 重啟服務,非常麻煩。
2.1、ApolloDemoTestApplication類
package com.cn.dl; import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.stereotype.Component; @SpringBootApplication @EnableApolloConfig public class ApolloDemoTestApplication { public static void main(String[] args) { SpringApplication.run(ApolloDemoTestApplication.class, args); } }
注意:這裡要加上@EnableApolloConfig 註解,否則依賴注入的Config=null
java.lang.IllegalStateException: Failed to execute CommandLineRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:816) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE] at com.cn.dl.ApolloDemoTestApplication.main(ApolloDemoTestApplication.java:13) [classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_161] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_161] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161] at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) [idea_rt.jar:na] Caused by: java.lang.NullPointerException: null at com.cn.dl.ApolloConfigurationChange.monitorApolloConfigurationChange(ApolloConfigurationChange.java:16) ~[classes/:na] at com.cn.dl.InitApolloConfigure.loadCommonConfig(InitApolloConfigure.java:53) ~[classes/:na] at com.cn.dl.InitApolloConfigure.run(InitApolloConfigure.java:31) ~[classes/:na] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE] ... 10 common frames omitted
2.2、PropertiesUtils類
package com.cn.dl; import java.util.Properties; /** * Created by Tiger on 2018/10/10. * 讀取公共apollo配置 */ public class PropertiesUtils { public static final String COMMON = "apollo-common"; public static final Properties properties = new Properties(); public String getString(String key){ return properties.getProperty(key); } public Integer getInteger(String key){ try { return Integer.parseInt(properties.getProperty(key)); }catch (Exception e){ return null; } } public Long getLong(String key){ try { return Long.parseLong(properties.getProperty(key)); }catch (Exception e){ return null; } } public Boolean getBoolean(String key){ try { return Boolean.parseBoolean(properties.getProperty(key)); }catch (Exception e){ return null; } } }
public static final String COMMON = "apollo-common";
注意:apollo-common是我自己本地測試的一個公共配置,可有可無
2.3、InitApolloConfigure類:讀取配置
package com.cn.dl;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Set;
/**
* Created by tiger on 2018/11/22.
*/
@Component
//order是用來指定初始順序,value越小,越早載入
@Order(value = -9)
public class InitApolloConfigure implements CommandLineRunner {
//從apollo獲取配置資訊
@ApolloConfig
private Config config;
/**
* commandLineRunner 目的就是在啟動之後可以載入所需要的配置檔案
* */
@Override
public void run(String... strings) throws Exception {
System.out.println("初始化>>>CommandLineRunner");
//載入公共配置
loadCommonConfig();
//載入指定model的配置
Set<String> configs = config.getPropertyNames();
if(configs != null && ! configs.isEmpty()){
configs.forEach(key -> {
PropertiesUtils.properties.setProperty(key,config.getProperty(key,null));
});
//監聽app.id中的key發生變化後就改變其值
ApolloConfigurationChange.monitorApolloConfigurationChange(PropertiesUtils.properties,config);
}
}
/**
* 載入公共配置檔案
* */
public void loadCommonConfig(){
Config commonConfig = ConfigService.getConfig(PropertiesUtils.COMMON);
if(commonConfig != null){
for(String key : commonConfig.getPropertyNames()){
PropertiesUtils.properties.setProperty(key,commonConfig.getProperty(key,null));
}
//監聽app.id中的key發生變化後就改變其值
ApolloConfigurationChange.monitorApolloConfigurationChange(PropertiesUtils.properties,config);
}
}
}
這裡使用了org.springframework.boot.CommandLineRunner這個介面,它的作用就是在啟動之後馬上載入配置,相當於servlet中init()方法,也可以用@PostConstruct註解。
2.4、ApolloConfigurationChange類
package com.cn.dl;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.model.ConfigChange;
import java.util.Properties;
import java.util.Set;
/**
* apollo中的值發生改變,覆蓋PropertiesUtils中鍵值
* Created by Tiger on 2018/11/22.
*/
public class ApolloConfigurationChange {
public static void monitorApolloConfigurationChange(Properties properties, Config config){
config.addChangeListener(configChangeEvent -> {
Set<String> keys = configChangeEvent.changedKeys();
for(String key : keys){
ConfigChange configChange = configChangeEvent.getChange(key);
//覆蓋舊值
PropertiesUtils.properties.setProperty(key,configChange.getNewValue());
System.out.println(configChange.getPropertyName()+" 的值改變了,原值:"+
configChange.getOldValue()+",新值:"+configChange.getNewValue());
}
});
}
}
當apollo中配置修改時,這裡就會監聽到並覆蓋PropertiesUtils中鍵值對
2.5、ApolloDemoController類:測試
package com.cn.dl;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Properties;
/**
* Created by Tiger 2018/10/10.
*/
@RestController
@RequestMapping("/apollo")
public class ApolloDemoController {
@GetMapping("/read_demo")
public Properties apolloReadDemo(){
return PropertiesUtils.properties;
}
}
2.6、application.properties
server.port=7089
注意:我在本地搭建apollo的時候8080埠被佔用了,所以這裡修改了埠號
三、測試
1、在apollo新增配置
2、vm options配置
3、調介面 127.0.0.1:7089/apollo/read_demo
{
"password": "DongLi#%qq123",
"model": "apolloTestTiger",
"url": "http://www.alibaba.com/",
"username": "[email protected]"
}
4、修改url的值,然後釋出,看日誌和返回的結果
釋出之後,立刻就監聽到了變化,調介面也是返回修改之後的結果
{
"password": "DongLi#%qq123",
"model": "apolloTestTiger",
"url": "http://www.baidu.com/",
"username": "[email protected]"
}
四、總結
用了apollo,發現很方便,比把配置放在resources下不知道方便了多少倍,非常推薦使用。