----------------------------------------------------------java
spring-cloud快速入門工程之j360-cloud-all:(歡迎star、fork)git
https://github.com/xuminwlt/j360-cloud-allgithub
spring cloud系列博客web
J360-cloud SpringCloud系列二:服務發現Discovery Service
spring
SpringCloud構建在Springboot基礎上,如何使用SpringBoot請轉移到shell
spring-boot入門工程之j360-boot:(歡迎star、fork)bootstrap
https://github.com/xuminwlt/j360-boot服務器
spring-boot官方地址app
http://projects.spring.io/spring-boot/
分佈式
Spring Cloud分佈式配置服務由服務器端和客戶端共同組成,Server端提供配置信息的存儲管理,客戶端完成配置信息的調度,工程結構以下
套用一個圖來解釋該部分在springCloud分佈式系統中的結構
上面的圖片說明了四個微服務以及各個服務之間的依賴關係。
configuration service 處於最頂端,黃色標識,並且被其餘微服務所依賴。
discovery service 處於最低端,藍色標識,同時也被其餘服務所依賴。
- bootstrap.yml
- application.yml
- 【注】建議採用bootstrap+application組合形式,通常bootstrap配置工程不可變參數,且在啓動時須要設定的內容,application配置可變參數
一、POM依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
二、註解
- configserver提供了HTTP,爲外部資源提供API配置的服務,只須要在Springboot程序中提供@EnableConfigServer註解便可。
- @EnableConfigServer
- 增長如下依賴 eureka(可選,做爲discover服務器必選)
三、配置文件
bootstrap.properties
spring.application.name=configserver spring.cloud.config.uri=http://localhost:8888
application.properties
server.port=8888 spring.cloud.config.server.git.uri=https://github.com/xuminwlt/config-repo
四、spring-boot:run
http://localhost:8888/configserver/application.properties
一、POM
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
二、配置
bootstrap.properties
spring.application.name=client spring.cloud.config.uri=http://localhost:8888
application.properties
server.port=8080 apply.message=local message user.username=xumin
三、spring-boot:run
四、http://localhost:8080/env 查看環境變量
五、http://localhost:8080/refresh post方法,更新client中的配置
【注】環境變量刷新
- post -> localhost:8080/refresh
- 定時
- 手動
默認的環境變量庫使用git服務,也可使用文件系統的服務
一、git服務
https://github.com/xuminwlt/config-repo
二、文件服務
使用 spring.profiles.active=native
環境變量倉庫使用3個變量:
- {application} 在客戶端映射到"spring.application.name"
- {profile} 在客戶端映射到"spring.active.profiles",使用逗號分隔
- {label}這是一個服務器端功能標籤「版本」的一組配置文件
當環境變量參數經過git更新後,客戶端自動更新:
1:可使用 post /refresh來執行,客戶端調用更新功能,configServer pull git完成後,更新環境變量信息,客戶端獲取最新的環境變量,而且更新
2:定時器執行:每隔X時間段更新一次
3:根據須要執行:只須要將定時器調用的更新接口暴露成服務形式調用
多客戶端更新服務
1:經過Spring Cloud Bus更新
2:其餘廣播形式調用接口
調用接口:
/** * 手動刷新git更新方案,每20S執行一次,能夠修改爲手動執行,同/refresh * @link RefreshEndpoint * */ public void refresh() { Map<String, Object> before = extract(context.getEnvironment() .getPropertySources()); addConfigFilesToEnvironment(); Set<String> keys = changes(before, extract(context.getEnvironment().getPropertySources())).keySet(); scope.refreshAll(); context.publishEvent(new EnvironmentChangeEvent(keys)); } @Configuration protected static class Empty { } private void addConfigFilesToEnvironment() { ConfigurableApplicationContext capture = null; try { capture = new SpringApplicationBuilder(Empty.class).showBanner(false) .web(false).environment(context.getEnvironment()).run(); MutablePropertySources target = context.getEnvironment().getPropertySources(); for (PropertySource<?> source : capture.getEnvironment().getPropertySources()) { String name = source.getName(); if (!standardSources.contains(name)) { if (target.contains(name)) { target.replace(name, source); } else { if (target.contains("defaultProperties")) { target.addBefore("defaultProperties", source); } else { target.addLast(source); } } } } } finally { while (capture != null) { capture.close(); ApplicationContext parent = capture.getParent(); if (parent instanceof ConfigurableApplicationContext) { capture = (ConfigurableApplicationContext) parent; } else { capture = null; } } } } private Map<String, Object> changes(Map<String, Object> before, Map<String, Object> after) { Map<String, Object> result = new HashMap<String, Object>(); for (String key : before.keySet()) { if (!after.containsKey(key)) { result.put(key, null); } else if (!equal(before.get(key), after.get(key))) { result.put(key, after.get(key)); } } for (String key : after.keySet()) { if (!before.containsKey(key)) { result.put(key, after.get(key)); } } return result; } private boolean equal(Object one, Object two) { if (one == null && two == null) { return true; } if (one == null || two == null) { return false; } return one.equals(two); } private Map<String, Object> extract(MutablePropertySources propertySources) { Map<String, Object> result = new HashMap<String, Object>(); for (PropertySource<?> parent : propertySources) { if (!standardSources.contains(parent.getName())) { extract(parent, result); } } return result; } private void extract(PropertySource<?> parent, Map<String, Object> result) { if (parent instanceof CompositePropertySource) { try { for (PropertySource<?> source : ((CompositePropertySource) parent) .getPropertySources()) { extract(source, result); } } catch (Exception e) { return; } } else if (parent instanceof EnumerablePropertySource) { for (String key : ((EnumerablePropertySource<?>) parent).getPropertyNames()) { result.put(key, parent.getProperty(key)); } } }