非spring boot (即spring) 使用/整合 Spring cloud Config 分散式配置中心

美式不加糖_發表於2019-03-04

非spring boot 使用Spring cloud Config (老版 spring 整合 spring cloud config ) || spring cloud config 搭建
個人部落格:https://eric-ly.github.io/

背景:想自己搭建一個分散式的配置中心,發現spring Cloud Config 不錯,(後臺基於git,可以配置webhook 實現熱更新、回滾,分環境配置等)與自己的期望相近。

雖然好用但是基於spring boot的,spring 與spring boot 還是有挺多巨別。為了能用在現有的 專案中,決定 想辦法整合一下,百度 google 都沒有現成的可以copy…

於是想自己實現下,查詢之後 按照一個大神的想法實現了下。中間遇到許多問題,不過更加了解spring了 也會繼續完善。java 新人 希望各位大神多多指導。

github:https://github.com/Eric-ly/hconfig

後面有專案的測試說明:

實現結果:

在spring 中 使用spring Cloud Config 功能,分專案/環境 獲取配置檔案,自動注入,自動更新 spring boot的註解無法相容 待稍後解決。

前提:

一個簡單的spring spring MVC 專案。

config server 配置好,github 配置好。 這個網上百度就有很多。

(在搭建spring cloud config (server and client)後,搭建註冊應用中心 eureka 和 rabbitMq 進行自動熱更新。)

實現方式:

1.建立自定義的ApplicationContext,先通過在web.xml中設定 contextClass 來指定應用使用自定義的ApplicationContext,

2.在自定義的applicationContext中 覆寫 建立environment的方法,用來定製 environment,把config server的配置資訊加入 應用

3.自定義的CloudEnvironment extends StandardServletEnvironment,擴充套件customizePropertySources方法,指定 配置的來源,然後放入 propertySource的list中,作為整個專案的 配置之一。

4.自定義propertySouce ,使用spring cloud client的ConfigClientProperties 作為 propertySouce的來源, 然後新增到PropertySource中

5.自定義配置類,將配置中心的配置按照單個/model 進行注入

後期實現:

(1)相容@refresh的註解,使 自動更新。

(2)通過修改name 獲取多個配置檔案。優化config server的檔案

(3)細化 回滾功能

(4)寫 攔截器,打成jar包,成為一個工具包,通過自定義註解 來使用。隱藏實現。成為一個通用的功能

最近有點忙,這個專案先達到能基本用,慢慢完善。

具體實現步驟:

1.增加pom 依賴,spring mvc ,spring cloud,logback 等

    <properties>
        <spring.version>4.2.9.RELEASE</spring.version>
        <jstl.version>1.2</jstl.version>
        <junit.version>4.11</junit.version>
        <logback.version>1.0.13</logback.version>
        <jcl-over-slf4j.version>1.7.5</jcl-over-slf4j.version>
        <spring.cloud.version>1.2.0.RELEASE</spring.cloud.version>
    </properties>
複製程式碼

2.建立自定義的ApplicationContext,先通過在web.xml中設定 contextClass 來指定自己的ApplicationContext,

contextClass

org.lybm.hconfig.clientWosb.config.CustomWebApplicationContext

ApplicationContext 是spring ioc 的體現,spring 中的容器。一般有幾種實現。
FileSystemXmlApplicationContext/ClassPathXmlApplicationContext/WebXmlApplicationContex

我們在搭建框架的時候一般通過註冊ContextLoaderListener 監聽 去自動獲取 初始化(這裡先去通過classContext的配置獲取,而且必須可以強轉為WebXmlApplicationContxt,如果沒設定 建立預設的)
,這裡為了使用spring boot的功能,我們需要自定義ApplicationContext
複製程式碼

在新定義的ApplicationContext 中我們使用自定義的Environment,為了把配置放到 environment中來使用。

public class CustomWebApplicationContext extends XmlWebApplicationContext {
	@Override
    protected ConfigurableEnvironment createEnvironment() {
        System.out.println("-------- loaded my CustomWebApplicationContext context");
        return new CloudEnvironment();
    }
 }
複製程式碼

3.建立 自定義的Environment,用來把 配置中心 config server的配置 放到環境中。

(1)重寫定製方法

自定義的CloudEnvironment extends StandardServletEnvironment,擴充套件customizePropertySources方法,指定 配置的來源,然後放入 propertySource的list中,作為整個專案的 配置之一。

這裡說一下,spring 的所有配置,包括system配置 ,jdni,自定義的properties等 都會放到 spring的environtment的propertySource的list中,用來使用。

    @Override
    protected void customizePropertySources(MutablePropertySources propertySources) {
        super.customizePropertySources(propertySources);
        try {
            //用來新增應用名到environment中
            propertySources.addLast( initResourcePropertySourceLocator() );
            //新增config Server的配置
            PropertySource<?> source = initConfigServicePropertySourceLocator(this);
            propertySources.addLast(source);
        } catch (Exception ex) {
            logger.warn("failed to initialize cloud config environment", ex);
        }
    }
複製程式碼

(2)獲取 config server的 配置資訊,生成propertySource ,建立一個來源。用到了spring cloud的方法

這裡說明一下,在配置ConfigClientProperties 連線資訊的時候, 後面的程式碼 會重新覆蓋 applicationName 所以這裡設定name是沒有意義的。 會從environment 中 獲取商品日嗯

    private PropertySource<?> initConfigServicePropertySourceLocator(Environment environment) {

        ConfigClientProperties configClientProperties = new ConfigClientProperties(environment);
        configClientProperties.setUri("http://localhost:9001/");
//        configClientProperties.setName("config-client");
        configClientProperties.setProfile("dev");
        configClientProperties.setLabel("master");

        logger.debug("will load the client configuration-------"+configClientProperties);
        ConfigServicePropertySourceLocator configServicePropertySourceLocator =
                new ConfigServicePropertySourceLocator(configClientProperties);

        return configServicePropertySourceLocator.locate(environment);
    }
複製程式碼

重新設定name的程式碼,如下, 這樣會導致我們連線獲取到的配置資訊不正確。

		override.setName(
				environment.resolvePlaceholders("${" + ConfigClientProperties.PREFIX
						+ ".name:${spring.application.name:application}}"));
複製程式碼

於是,我在 進行這一步前 將正確的 name資訊, 加入到environment中,就可以找到 正常使用。

(3)新增 應用相關配置 到environment中。

在查詢相關原始碼後發現。我只需要 將一個resource 物件放入 environment的 資源 list中就可以,這裡我新建一個properties,寫入配置,然後封裝成resource 就可以了。

cloud-config-context.properties
spring.application.name=config-client
demo=demo
複製程式碼

具體實現:

	Resource resource = new DefaultResourceLoader(this.getClass().getClassLoader()).
getResource("classpath:cloud-config-context.properties");
	
	resourcePropertySource = new ResourcePropertySource(resource);
複製程式碼

這裡學習的過程 花費了一些時間。瞭解了 environment,propertySource 等spring 載入配置資訊的程式碼。一些相關知識會在後續貼出來

4.現在environment 重寫好了,建立配置資訊類

我們目前可以通過兩種方式獲取配置,

(1)單個配置的獲取。

    //單獨一個欄位的獲取
    @Value("${test}")
    private String test;
 這麼寫 如果沒有test ,程式會報錯,啟動不了, 所以 不要用這種寫法
 
     //單獨一個欄位的獲取
    @Value("${xxx:x}")
    private String test;
單個欄位 推薦這麼寫,如果xxx沒有,則使用預設值x ,這樣比較符合 業務場景
複製程式碼

(2)按照配置資訊類 獲取

如下,將配置資訊對映成一個model,可以將統一字首 如wosb的配置資訊 放到一個類裡,這樣方便管理,在寫配置的時候 也好區分,就像一個一個配置檔案。

@ConfigurationProperties(prefix = "wosb")
@Data
public class WosbProperties {
    private String test;
    private String demo;
    private String name;
    private String paht;
}
複製程式碼

(2.2)將配置類 注入,兩種方式,

a. 通過註解,增加@Configuration,將這個類注入到 容器中

註解定義
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
複製程式碼

b.通過配置PropertySourcesPlaceHolderConfigurer,不太推薦

@Configuration
@EnableConfigurationProperties({WosbProperties.class})
public class PropertiesConfigurer {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}
複製程式碼

5.繼承完成,使用/測試

(1)建立controller

(2)使用

    @Autowired
    private SearchProperties searchProperties;
    //單獨一個欄位的獲取
    @Value("${xxx:x}")
    private String test;
複製程式碼

(3)可以注入Environment env 來檢視當前的environment資訊。

專案說明:

github:https://github.com/Eric-ly/hconfig

github的配置檔案地址:https://github.com/Eric-ly/hconfig-properties

cloudeureka: spring boot的應用註冊中心

ConfligClientNoSpringBoot: 非spring boot 應用 使用 應用配置中心

hconfigclient:spring boot的 應用配置中心的 客戶端

hconfigserver:spring boot的 應用配置中心的服務端

使用說明:

1.啟動 應用註冊中心

(1)入口類:EurekaServerApplication IDE debug 或者用命令

(2)配置:

server.port=8761
eureka.instance.hostname=localhost
複製程式碼

2.啟動 配置中心的服務端

(1)入口類:ConfigServerApplication

(2)配置:

埠:

spring.application.name=config-server
server.port=9001
複製程式碼

gitlab :來源

spring.cloud.config.server.git.uri=https://github.com/Eric-ly/hconfig-properties.git
spring.cloud.config.server.git.searchPaths=configRepo
spring.cloud.config.server.git.username=
spring.cloud.config.server.git.password=

spring.cloud.config.server.git.basedir=src/main/resource/config
# //載入到ConfigServer專案所在的本地目錄的位置, 可以不用配置
複製程式碼

訊息匯流排,用來自動熱更新,配置的是mq的地址,需要自己啟

#   新增cloud bus 訊息匯流排,配合webhook 實現 所有client的訊息熱更新
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
## 重新整理時,關閉安全驗證
management.security.enabled=false
## 開啟訊息跟蹤
spring.cloud.bus.trace.enabled=true
複製程式碼

註冊中心:

#註冊中心地址
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
複製程式碼

3.啟動 非spring boot的 ConfligClientNoSpringBoot

(1)配置 應用名

cloud-config-context.properties

spring.application.name=config-client
複製程式碼

(2)IDE新增tomcat,然後啟動

(3)測試

http://localhost:8888/hello

結果: 配置檔案都讀取到了

search-pproperties : collection :{{engine}} demo: {{solr}} ||| wosb-properties: demo : {{ a}} name: {{ wosb }} path: {{ /}} single value : test?{{ abcdegggg }}
複製程式碼

4.spring boot的 配置中新 客戶端( 自動熱更新)hconfigclient

(1)入口類 entryApplication

(2)配置:

(1) 應用名+ 配置中心的 服務端

spring.application.name=config-client
spring.cloud.config.label=master
spring.cloud.config.profile=dev
spring.cloud.config.uri= http://localhost:9001/
server.port=8888
複製程式碼

(2)

#註冊中心地址
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
複製程式碼

(3)

## 重新整理時,關閉安全驗證
management.security.enabled=false
## 開啟訊息跟蹤
spring.cloud.bus.trace.enabled=true

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
複製程式碼

(4) 測試

(提交程式碼觸發post請求給bus/refresh ----server端接收到請求併傳送給Spring Cloud Bus
----Spring Cloud bus接到訊息並通知給其它客戶端 ----其它客戶端接收到通知,請求Server端獲取最新配置
----全部客戶端均獲取到最新的配置)
複製程式碼

相關文章