非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端獲取最新配置
----全部客戶端均獲取到最新的配置)
複製程式碼