1. 程式人生 > >springboot-監聽apollo配置

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這個介面,它的作用就是在啟動之後馬上載入配置,相當於servletinit()方法,也可以用@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下不知道方便了多少倍,非常推薦使用。