後期更新內容移步到我的網站:www.upheart.tophtml
Spring Cloud版本爲Finchley.RELEASEjava
建立服務註冊中心node
引入spring-cloud-starter-netflix-eureka-server的依賴linux
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
複製代碼
啓動一個服務註冊中心,只須要一個註解@EnableEurekaServer,這個註解須要在springboot工程的啓動application類上加:git
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run( EurekaServerApplication.class, args );
}
}
複製代碼
eureka是一個高可用的組件,它沒有後端緩存,每個實例註冊以後須要向註冊中心發送心跳(所以能夠在內存中完成),在默認狀況下erureka server也是一個eureka client ,必需要指定一個 server。eureka server的配置文件appication.yml:github
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
application:
name: eurka-server
複製代碼
經過eureka.client.registerWithEureka:false和fetchRegistry:false來代表本身是一個eureka serverweb
eureka server 是有界面的,啓動工程,打開瀏覽器訪問:http://localhost:8761spring
建立一個服務提供者 (eureka client)sql
當client向server註冊時,它會提供一些元數據,例如主機和端口,URL,主頁等。Eureka server 從每一個client實例接收心跳消息。 若是心跳超時,則一般將該實例從註冊server中刪除json
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
複製代碼
經過註解@EnableEurekaClient 代表本身是一個eurekaclient
@SpringBootApplication
@EnableEurekaClient
@RestController
public class ServiceHiApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceHiApplication.class, args );
}
@Value("${server.port}")
String port;
@RequestMapping("/hi")
public String home(@RequestParam(value = "name", defaultValue = "forezp") String name) {
return "hi " + name + " ,i am from port:" + port;
}
}
複製代碼
僅僅@EnableEurekaClient是不夠的,還須要在配置文件中註明本身的服務註冊中心的地址,application.yml配置文件以下:
server:
port: 8762
spring:
application:
name: service-hi
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
複製代碼
須要指明spring.application.name,這個很重要,這在之後的服務與服務之間相互調用通常都是根據這個name 啓動工程,打開http://localhost:8761 ,即eureka server 的網址
你會發現一個服務已經註冊在服務中了,服務名爲SERVICE-HI ,端口爲8762
這時打開 http://localhost:8762/hi?name=forezp
Spring cloud有兩種服務調用方式,一種是ribbon+restTemplate,另外一種是feign
ribbon是一個負載均衡客戶端,能夠很好的控制htt和tcp的一些行爲。Feign默認集成了ribbon
在工程的啓動類中,經過@EnableDiscoveryClient向服務中心註冊;而且向程序的ioc注入一個bean: restTemplate;並經過@LoadBalanced註解代表這個restRemplate開啓負載均衡的功能
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceRibbonApplication.class, args );
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
複製代碼
寫一個測試類HelloService,經過以前注入ioc容器的restTemplate來消費service-hi服務的「/hi」接口,在這裏咱們直接用的程序名替代了具體的url地址,在ribbon中它會根據服務名來選擇具體的服務實例,根據服務實例在請求的時候會用具體的url替換掉服務名,代碼以下:
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
public String hiService(String name) {
return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
}
}
複製代碼
寫一個controller,在controller中用調用HelloService 的方法,代碼以下:
@RestController
public class HelloControler {
@Autowired
HelloService helloService;
@GetMapping(value = "/hi")
public String hi(@RequestParam String name) {
return helloService.hiService( name );
}
}
複製代碼
在瀏覽器上屢次訪問http://localhost:8764/hi?name=forezp
說明當咱們經過調用restTemplate.getForObject(「http://SERVICE-HI/hi?name=」+name,String.class)方法時,已經作了負載均衡,訪問了不一樣的端口的服務實例
Feign是一個聲明式的僞Http客戶端,它使得寫Http客戶端變得更簡單。使用Feign,只須要建立一個接口並註解。它具備可插拔的註解特性,可以使用Feign 註解和JAX-RS註解。Feign支持可插拔的編碼器和解碼器。Feign默認集成了Ribbon,並和Eureka結合,默認實現了負載均衡的效果
簡而言之:
Feign 採用的是基於接口的註解
Feign 整合了ribbon,具備負載均衡的能力
整合了Hystrix,具備熔斷的能力
複製代碼
引入Feign的起步依賴spring-cloud-starter-feign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
複製代碼
在程序的啓動類ServiceFeignApplication ,加上@EnableFeignClients註解開啓Feign的功能:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceFeignApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceFeignApplication.class, args );
}
}
複製代碼
定義一個feign接口,經過@ FeignClient(「服務名」),來指定調用哪一個服務。好比在代碼中調用了service-hi服務的「/hi」接口,代碼以下:
@FeignClient(value = "service-hi")
public interface SchedualServiceHi {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String sayHiFromClientOne(@RequestParam(value = "name") String name);
}
複製代碼
在Web層的controller層,對外暴露一個"/hi"的API接口,經過上面定義的Feign客戶端SchedualServiceHi 來消費服務。代碼以下:
@RestController
public class HiController {
//編譯器報錯,無視。 由於這個Bean是在程序啓動的時候注入的,編譯器感知不到,因此報錯。
@Autowired
SchedualServiceHi schedualServiceHi;
@GetMapping(value = "/hi")
public String sayHi(@RequestParam String name) {
return schedualServiceHi.sayHiFromClientOne( name );
}
}
複製代碼
啓動程序,屢次訪問http://localhost:8765/hi?name=forezp
在Spring Cloud能夠用RestTemplate+Ribbon和Feign來調用。爲了保證其高可用,單個服務一般會集羣部署。因爲網絡緣由或者自身的緣由,服務並不能保證100%可用,若是單個服務出現問題,調用這個服務就會出現線程阻塞,此時如有大量的請求涌入,Servlet容器的線程資源會被消耗完畢,致使服務癱瘓。服務與服務之間的依賴性,故障會傳播,會對整個微服務系統形成災難性的嚴重後果,這就是服務故障的「雪崩」效應
Netflix開源了Hystrix組件,實現了斷路器模式,SpringCloud對這一組件進行了整合
較底層的服務若是出現故障,會致使連鎖故障。當對特定的服務的調用的不可用達到一個閥值(Hystric 是5秒20次) 斷路器將會被打開
斷路打開後,可用避免連鎖故障,fallback方法能夠直接返回一個固定值
加入spring-cloud-starter-netflix-hystrix的起步依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
複製代碼
在程序的啓動類ServiceRibbonApplication 加@EnableHystrix註解開啓Hystrix:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableHystrix
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceRibbonApplication.class, args );
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
複製代碼
改造HelloService類,在hiService方法上加上@HystrixCommand註解。該註解對該方法建立了熔斷器的功能,並指定了fallbackMethod熔斷方法,熔斷方法直接返回了一個字符串,字符串爲"hi,"+name+",sorry,error!",代碼以下:
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String hiService(String name) {
return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
}
public String hiError(String name) {
return "hi,"+name+",sorry,error!";
}
}
複製代碼
啓動:service-ribbon 工程,當咱們訪問http://localhost:8764/hi?name=forezp
此時關閉 service-hi 工程,當咱們再訪問http://localhost:8764/hi?name=forezp
當 service-hi 工程不可用的時候,service-ribbon調用 service-hi的API接口時,會執行快速失敗,直接返回一組字符串,而不是等待響應超時,這很好的控制了容器的線程阻塞
Feign是自帶斷路器的,在D版本的Spring Cloud以後,它沒有默認打開。須要在配置文件中配置打開它,在配置文件加如下代碼:
feign.hystrix.enabled=true
複製代碼
基於service-feign工程進行改造,只須要在FeignClient的SchedualServiceHi接口的註解中加上fallback的指定類就好了:
@FeignClient(value = "service-hi",fallback = SchedualServiceHiHystric.class)
public interface SchedualServiceHi {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String sayHiFromClientOne(@RequestParam(value = "name") String name);
}
複製代碼
SchedualServiceHiHystric須要實現SchedualServiceHi 接口,並注入到Ioc容器中,代碼以下:
@Component
public class SchedualServiceHiHystric implements SchedualServiceHi {
@Override
public String sayHiFromClientOne(String name) {
return "sorry "+name;
}
}
複製代碼
啓動四servcie-feign工程,瀏覽器打開http://localhost:8765/hi?name=forezp,注意此時service-hi工程沒有啓動,網頁顯示:
sorry forezp
複製代碼
打開service-hi工程,再次訪問,瀏覽器顯示:
hi forezp,i am from port:8762
複製代碼
這證實斷路器起到做用了
Hystrix Dashboard是做爲斷路器狀態的一個組件,提供了數據監控和友好的圖形化界面
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
複製代碼
在程序的入口ServiceHiApplication類,加上@EnableHystrix註解開啓斷路器,這個是必須的,而且須要在程序中聲明斷路點HystrixCommand;加上@EnableHystrixDashboard註解,開啓HystrixDashboard
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@RestController
@EnableHystrix
@EnableHystrixDashboard
@EnableCircuitBreaker
public class ServiceHiApplication {
/** * 訪問地址 http://localhost:8762/actuator/hystrix.stream * @param args */
public static void main(String[] args) {
SpringApplication.run( ServiceHiApplication.class, args );
}
@Value("${server.port}")
String port;
@RequestMapping("/hi")
@HystrixCommand(fallbackMethod = "hiError")
public String home(@RequestParam(value = "name", defaultValue = "forezp") String name) {
return "hi " + name + " ,i am from port:" + port;
}
public String hiError(String name) {
return "hi,"+name+",sorry,error!";
}
}
複製代碼
打開http://localhost:8762/actuator/hystrix.stream,能夠看到一些具體的數據
打開localhost:8762/hystrix
當咱們有不少個服務的時候,這就須要聚合因此服務的Hystrix Dashboard的數據了
看單個的Hystrix Dashboard的數據並無什麼多大的價值,要想看這個系統的Hystrix Dashboard數據就須要用到Hystrix Turbine。Hystrix Turbine將每一個服務Hystrix Dashboard數據進行了整合
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
複製代碼
在其入口類ServiceTurbineApplication加上註解@EnableTurbine,開啓turbine,@EnableTurbine註解包含了@EnableDiscoveryClient註解,即開啓了註冊服務
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@RestController
@EnableHystrix
@EnableHystrixDashboard
@EnableCircuitBreaker
@EnableTurbine
public class ServiceTurbineApplication {
/** * http://localhost:8764/turbine.stream */
public static void main(String[] args) {
SpringApplication.run( ServiceTurbineApplication.class, args );
}
}
複製代碼
配置文件application.yml:
server:
port: 8764
spring:
application:
name: service-turbine
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
endpoints:
web:
exposure:
include: "*"
cors:
allowed-origins: "*"
allowed-methods: "*"
turbine:
app-config: service-hi,service-lucy
aggregator:
clusterConfig: default
clusterNameExpression: new String("default")
combine-host: true
instanceUrlSuffix:
default: actuator/hystrix.stream
複製代碼
打開瀏覽器輸入:http://localhost:8764/turbine.stream
在Spring Cloud微服務系統中,一種常見的負載均衡方式是,客戶端的請求首先通過負載均衡(zuul、Ngnix),再到達服務網關(zuul集羣),而後再到具體的服務,服務統一註冊到高可用的服務註冊中心集羣,服務的全部的配置文件由配置服務管理配置服務的配置文件放在git倉庫,方便開發人員隨時改配置
Zuul的主要功能是路由轉發和過濾器。路由功能是微服務的一部分,好比/api/user轉發到到user服務,/api/shop轉發到到shop服務。zuul默認和Ribbon結合實現了負載均衡的功能
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
複製代碼
在其入口applicaton類加上註解@EnableZuulProxy,開啓zuul的功能:
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
@EnableDiscoveryClient
public class ServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceZuulApplication.class, args );
}
}
複製代碼
加上配置文件application.yml加上如下的配置代碼:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8769
spring:
application:
name: service-zuul
zuul:
routes:
api-a:
path: /api-a/**
serviceId: service-ribbon
api-b:
path: /api-b/**
serviceId: service-feign
複製代碼
首先指定服務註冊中心的地址爲http://localhost:8761/eureka/,服務的端口爲8769,服務名爲service-zuul;以/api-a/ 開頭的請求都轉發給service-ribbon服務;以/api-b/開頭的請求都轉發給service-feign服務;
zuul不只只是路由,而且還能過濾,作一些安全驗證
@Component
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if(accessToken == null) {
log.warn("token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
}catch (Exception e){}
return null;
}
log.info("ok");
return null;
}
}
複製代碼
filterType:返回一個字符串表明過濾器的類型,在zuul中定義了四種不一樣生命週期的過濾器類型,具體以下:
pre:路由以前
routing:路由之時
post: 路由以後
error:發送錯誤調用
複製代碼
filterOrder:過濾的順序 shouldFilter:這裏能夠寫邏輯判斷,是否要過濾,true,永遠過濾 run:過濾器的具體邏輯。可用很複雜,包括查sql,nosql去判斷該請求到底有沒有權限訪問
Spring Cloud Gateway是Spring Cloud官方推出的第二代網關框架,取代Zuul網關。網關做爲流量的,在微服務系統中有着很是做用,網關常見的功能有路由轉發、權限校驗、限流控制等做用
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
複製代碼
在spring cloud gateway中使用RouteLocator的Bean進行路由轉發,將請求進行處理,最後轉發到目標的下游服務。在本案例中,會將請求轉發到http://httpbin.org:80這個地址上。代碼以下:
@SpringBootApplication
@RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(p -> p
.path("/get")
.filters(f -> f.addRequestHeader("Hello", "World"))
.uri("http://httpbin.org:80"))
.build();
}
}
複製代碼
在上面的myRoutes方法中,使用了一個RouteLocatorBuilder的bean去建立路由,除了建立路由RouteLocatorBuilder可讓你添加各類predicates和filters,predicates斷言的意思,顧名思義就是根據具體的請求的規則,由具體的route去處理,filters是各類過濾器,用來對請求作各類判斷和修改
上面建立的route可讓請求「/get」請求都轉發到「httpbin.org/get」。在route…
啓動springboot項目,在瀏覽器上http://localhost:8080/get,瀏覽器顯示以下:
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "max-age=0",
"Connection": "close",
"Cookie": "_ga=GA1.1.412536205.1526967566; JSESSIONID.667921df=node01oc1cdl4mcjdx1mku2ef1l440q1.node0; screenResolution=1920x1200",
"Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:60036\"",
"Hello": "World",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"X-Forwarded-Host": "localhost:8080"
},
"origin": "0:0:0:0:0:0:0:1, 210.22.21.66",
"url": "http://localhost:8080/get"
}
複製代碼
可見當咱們向gateway工程請求「/get」,gateway會將工程的請求轉發到「httpbin.org/get」,而且在轉發之…
注意HTTPBin展現了請求的header hello和值world
使用Hystrix 在spring cloud gateway中可使用Hystrix。Hystrix是 spring cloud中一個服務熔斷降級的組件,在微服務系統有着十分重要的做用 Hystrix是 spring cloud gateway中是以filter的形式使用的,代碼以下:
@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
String httpUri = "http://httpbin.org:80";
return builder.routes()
.route(p -> p
.path("/get")
.filters(f -> f.addRequestHeader("Hello", "World"))
.uri(httpUri))
.route(p -> p
.host("*.hystrix.com")
.filters(f -> f
.hystrix(config -> config
.setName("mycmd")
.setFallbackUri("forward:/fallback")))
.uri(httpUri))
.build();
}
複製代碼
在上面的代碼中,咱們使用了另一個router,該router使用host去斷言請求是否進入該路由,當請求的host有「*.hystrix.com」,都會進入該router,該router中有一個hystrix的filter,該filter能夠配置名稱、和指向性fallback的邏輯的地址,好比本案例中重定向到了「/fallback」
如今寫的一個「/fallback」的l邏輯:
@RequestMapping("/fallback")
public Mono<String> fallback() {
return Mono.just("fallback");
}
複製代碼
Mono是一個Reactive stream,對外輸出一個「fallback」字符串
使用curl執行如下命令:
curl --dump-header - --header 'Host: www.hystrix.com' http://localhost:8080/delay/3
複製代碼
返回的響應爲:
fallback
複製代碼
可見,帶hostwww.hystrix.com的請求執行了hystrix的fallback的邏輯
在分佈式系統中,因爲服務數量巨多,爲了方便服務配置文件統一管理,實時更新,因此須要分佈式配置中心組件。在Spring Cloud中,有分佈式配置中心組件spring cloud config ,它支持配置服務放在配置服務的內存中(即本地),也支持放在遠程Git倉庫中。在spring cloud config 組件中,分兩個角色,一是config server,二是config client
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
複製代碼
在程序的入口Application類加上@EnableConfigServer註解開啓配置服務器的功能,代碼以下:
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
複製代碼
須要在程序的配置文件application.properties文件配置如下:
spring.application.name=config-server
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/forezp/SpringcloudConfig/
spring.cloud.config.server.git.searchPaths=respo
spring.cloud.config.label=master
spring.cloud.config.server.git.username=
spring.cloud.config.server.git.password=
複製代碼
spring.cloud.config.server.git.uri:配置git倉庫地址
spring.cloud.config.server.git.searchPaths:配置倉庫路徑
spring.cloud.config.label:配置倉庫的分支
spring.cloud.config.server.git.username:訪問git倉庫的用戶名
spring.cloud.config.server.git.password:訪問git倉庫的用戶密碼
複製代碼
若是Git倉庫爲公開倉庫,能夠不填寫用戶名和密碼,若是是私有倉庫須要填寫
遠程倉庫https://github.com/forezp/SpringcloudConfig/ 中有個文件config-client-dev.properties文件中有一個屬性:
foo = foo version 3
複製代碼
啓動程序:訪問http://localhost:8888/foo/dev
{"name":"foo","profiles":["dev"],"label":"master",
"version":"792ffc77c03f4b138d28e89b576900ac5e01a44b","state":null,"propertySources":[]}
複製代碼
證實配置服務中心能夠從遠程程序獲取配置信息
http請求地址和資源文件映射以下:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
複製代碼
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
複製代碼
其配置文件bootstrap.properties:
spring.application.name=config-client
spring.cloud.config.label=master
spring.cloud.config.profile=dev
spring.cloud.config.uri= http://localhost:8888/
server.port=8881
複製代碼
spring.cloud.config.label 指明遠程倉庫的分支
spring.cloud.config.profile
dev開發環境配置文件
test測試環境
pro正式環境
spring.cloud.config.uri= http://localhost:8888/ 指明配置服務中心的網址
複製代碼
程序的入口類,寫一個API接口「/hi」,返回從配置中心讀取的foo變量的值,代碼以下:
@SpringBootApplication
@RestController
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
@Value("${foo}")
String foo;
@RequestMapping(value = "/hi")
public String hi(){
return foo;
}
}
複製代碼
打開網址訪問:http://localhost:8881/hi,網頁顯示:
foo version 3
這就說明,config-client從config-server獲取了foo的屬性,而config-server是從git倉庫讀取的
Spring Cloud Bus 將分佈式的節點用輕量的消息代理鏈接起來。它能夠用於廣播配置文件的更改或者服務之間的通信,也能夠用於監控
加上起步依賴spring-cloud-starter-bus-amqp
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
複製代碼
在配置文件application.properties中加上RabbitMq的配置,包括RabbitMq的地址、端口,用戶名、密碼。並須要加上spring.cloud.bus的三個配置,具體以下:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.cloud.bus.enabled=true
spring.cloud.bus.trace.enabled=true
management.endpoints.web.exposure.include=bus-refresh
複製代碼
ConfigClientApplication啓動類代碼以下:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@RestController
@RefreshScope
public class ConfigClientApplication {
/** * http://localhost:8881/actuator/bus-refresh */
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
@Value("${foo}")
String foo;
@RequestMapping(value = "/hi")
public String hi(){
return foo;
}
}
複製代碼
依次啓動eureka-server、confg-cserver,啓動兩個config-client,端口爲:888一、8882
訪問http://localhost:8881/hi 或者http://localhost:8882/hi 瀏覽器顯示:
foo version 3
複製代碼
這時咱們去代碼倉庫將foo的值改成「foo version 4」,即改變配置文件foo的值。若是是傳統的作法,須要重啓服務,才能達到配置文件的更新。此時,咱們只須要發送post請求:http://localhost:8881/actuator/bus-refresh,你會發現config-client會從新讀取配置文件
/actuator/bus-refresh接口能夠指定服務,即便用"destination"參數,好比 「/actuator/bus-refresh?destination=customers:**」 即刷新服務名爲customers的全部服務
當git文件更改的時候,經過pc端用post 向端口爲8882的config-client發送請求/bus/refresh/;此時8882端口會發送一個消息,由消息總線向其餘服務傳遞,從而使整個微服務集羣都達到更新配置文件
Spring Cloud Sleuth 主要功能就是在分佈式系統中提供追蹤解決方案,而且兼容支持了 zipkin,你只須要在pom文件中引入相應的依賴便可
微服務架構上經過業務來劃分服務的,經過REST調用,對外暴露的一個接口,可能須要不少個服務協同才能完成這個接口功能,若是鏈路上任何一個服務出現問題或者網絡超時,都會造成致使接口調用失敗。隨着業務的不斷擴張,服務之間互相調用會愈來愈複雜
有三個工程組成:一個server-zipkin,它的主要做用使用ZipkinServer 的功能,收集調用數據,並展現;一個service-hi,對外暴露hi接口;一個service-miya,對外暴露miya接口;這兩個service能夠相互調用;而且只有調用了,server-zipkin纔會收集數據的,這就是爲何叫服務追蹤了。
構建server-zipkin
在spring Cloud爲F版本的時候,已經不須要本身構建Zipkin Server了,只須要下載jar便可,下載地址:
下載完成jar 包以後,須要運行jar,以下:
java -jar zipkin-server-2.10.1-exec.jar
訪問瀏覽器localhost:9411
建立service-hi
在其pom引入起步依賴spring-cloud-starter-zipkin
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
複製代碼
在其配置文件application.yml指定zipkin server的地址,經過配置「spring.zipkin.base-url」指定:
server.port=8988
spring.zipkin.base-url=http://localhost:9411
spring.application.name=service-hi
複製代碼
經過引入spring-cloud-starter-zipkin依賴和設置spring.zipkin.base-url就能夠了
對外暴露接口:
package com.forezp;
import brave.sampler.Sampler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.logging.Level;
import java.util.logging.Logger;
@SpringBootApplication
@RestController
public class ServiceHiApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHiApplication.class, args);
}
private static final Logger LOG = Logger.getLogger(ServiceHiApplication.class.getName());
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@RequestMapping("/hi")
public String callHome(){
LOG.log(Level.INFO, "calling trace service-hi ");
return restTemplate.getForObject("http://localhost:8989/miya", String.class);
}
@RequestMapping("/info")
public String info(){
LOG.log(Level.INFO, "calling trace service-hi ");
return "i'm service-hi";
}
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
}
複製代碼
建立service-miya
建立過程痛service-hi,引入相同的依賴,配置下spring.zipkin.base-url
對外暴露接口:
package com.forezp;
import brave.sampler.Sampler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.logging.Level;
import java.util.logging.Logger;
@SpringBootApplication
@RestController
public class ServiceMiyaApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceMiyaApplication.class, args);
}
private static final Logger LOG = Logger.getLogger(ServiceMiyaApplication.class.getName());
@RequestMapping("/hi")
public String home(){
LOG.log(Level.INFO, "hi is being called");
return "hi i'm miya!";
}
@RequestMapping("/miya")
public String info(){
LOG.log(Level.INFO, "info is being called");
return restTemplate.getForObject("http://localhost:8988/info",String.class);
}
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
}
複製代碼
依次啓動上面的工程,打開瀏覽器訪問:http://localhost:9411/
Spring Cloud 版本爲Greenwich.RELEASE
Nacos 致力於幫助您發現、配置和管理微服務。Nacos 提供了一組簡單易用的特性集,幫助您快速實現動態服務發現、服務配置、服務元數據及流量管理
是Spring Cloud中的服務註冊發現組件,相似於Consul、Eureka,同時它又提供了分佈式配置中心的功能,這點和Consul的config相似,支持熱加載
Nacos 的關鍵特性包括:
服務發現和服務健康監測 動態配置服務,帶管理界面,支持豐富的配置維度 動態 DNS 服務 服務及其元數據管理
Nacos下載
Nacos依賴於Java環境,因此必須安裝Java環境。而後從官網下載Nacos的解壓包,安裝穩定版的,下載地址:github.com/alibaba/nac…
本次案例下載的版本爲1.0.0 ,下載完成後,解壓,在解壓後的文件的/bin目錄下,windows系統點擊startup.cmd就能夠啓動nacos。linux或mac執行如下命令啓動nacos
sh startup.sh -m standalone
啓動時會在控制檯,打印相關的日誌。nacos的啓動端口爲8848,在啓動時要保證端口不被佔用。珠穆拉馬峯的高度是8844,nacos的端口是8848,有點巧合
啓動成功,在瀏覽器上訪問:http://localhost:8848/nacos,會跳轉到登錄界面,默認的登錄用戶名爲nacos,密碼也爲nacos
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.9.0.RELEASE</version>
</dependency>
複製代碼
在工程的配置文件application.yml作相關的配置,配置以下:
server:
port: 8762
spring:
application:
name: nacos-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
複製代碼
在上述的配置的中,程序的啓動端口爲8762,應用名爲nacos-provider,向nacos server註冊的地址爲127.0.0.1:8848
而後在Spring Boot的啓動文件NacosProviderApplication加上@EnableDiscoveryClient註解,代碼以下:
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {
public static void main(String[] args) {
SpringApplication.run(NacosProviderApplication.class, args);
}
}
複製代碼
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
<version>0.9.0.RELEASE</version>
</dependency>
複製代碼
在bootstrap.yml(必定是bootstrap.yml文件,不是application.yml文件)文件配置如下內容:
spring:
application:
name: nacos-provider
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
prefix: nacos-provider
profiles:
active: dev
複製代碼
在上面的配置中,配置了nacos config server的地址,配置的擴展名是ymal(目前僅支持ymal和properties)。注意是沒有配置server.port的,sever.port的屬性在nacos中配置。上面的配置是和Nacos中的dataId 的格式是對應的,nacos的完整格式以下:
${prefix}-${spring.profile.active}.${file-extension}
複製代碼
prefix 默認爲 spring.application.name 的值,也能夠經過配置項 spring.cloud.nacos.config.prefix來配置 spring.profile.active 即爲當前環境對應的 profile,注意:當 spring.profile.active 爲空時,對應的鏈接符 - 也將不存在,dataId 的拼接格式變成 ${prefix}.${file-extension} file-exetension 爲配置內容的數據格式,能夠經過配置項 spring.cloud.nacos.config.file-extension 來配置。目前只支持 properties 和 yaml 類型 啓動nacos,登錄localhost:8848/nacos,建立一個data id
寫一個RestController,在Controller上添加 @RefreshScope 實現配置的熱加載。代碼以下:
@RestController
@RefreshScope
public class ConfigController {
@Value("${username:lily}")
private String username;
@RequestMapping("/username")
public String get() {
return username;
}
}
複製代碼
啓動工程nacos-provider,在瀏覽器上訪問localhost:8761/username,能夠返回在nacos控制檯上配置的username。在nacos 網頁上更改username的配置,在不重啓nacos-provider工程的狀況下,從新訪問localhost:8761/username,返回的事修改後的值,可見nacos做爲配置中心實現了熱加載功能