1. Spring Cloud簡(jiǎn)介
Spring Cloud只是將各家公司開(kāi)發(fā)的比較成熟瘟滨、經(jīng)得起實(shí)際考驗(yàn)的服務(wù)框架組合起來(lái)翠储,通過(guò)Spring Boot風(fēng)格進(jìn)行再封裝,屏蔽掉了復(fù)雜的配置和實(shí)現(xiàn)原理,最終給開(kāi)發(fā)者留出了一套簡(jiǎn)單易懂、易部署和易維護(hù)的分布式系統(tǒng)開(kāi)發(fā)工具包饺鹃。
Spring Cloud官網(wǎng):https://spring.io/projects/spring-cloud/
Spring Cloud的子項(xiàng)目,大致可分成兩類:
- 一類是對(duì)現(xiàn)有成熟框架“Spring Boot化”的封裝和抽象
- 另一類是開(kāi)發(fā)了一部分分布式系統(tǒng)的基礎(chǔ)設(shè)施的實(shí)現(xiàn)
常見(jiàn)的遠(yuǎn)程調(diào)用方式有RPC和HTTP:
- RPC特點(diǎn):基于Socket、自定義數(shù)據(jù)格式悔详、速度快
- HTTP特點(diǎn):基于TCP/IP镊屎、規(guī)定數(shù)據(jù)傳輸格式、消息封裝比較臃腫伟端、傳輸速度比較慢杯道、對(duì)服務(wù)提供和調(diào)用方式?jīng)]有任何技術(shù)限定匪煌,自由靈活责蝠,更符合微服務(wù)理念
- 微服務(wù)更加強(qiáng)調(diào)的是獨(dú)立、自治萎庭、靈活霜医,而RPC方式的限制較多,因此微服務(wù)框架中一般都會(huì)采用基于HTTP的Rest風(fēng)格服務(wù)
2. Spring Cloud Netflix Eureka
Eureka是一個(gè)基于REST的服務(wù)驳规,主要用于定位運(yùn)行在AWS域中的中間層服務(wù)肴敛,以達(dá)到負(fù)載均衡和中間層服務(wù)故障轉(zhuǎn)移的目的。
Eureka包含兩個(gè)組件:Eureka Server和Eureka Client
- Eureka Server提供服務(wù)注冊(cè)服務(wù)吗购,各個(gè)節(jié)點(diǎn)啟動(dòng)后医男,會(huì)在Eureka Server中進(jìn)行注冊(cè),這樣Eureka Server中的服務(wù)注冊(cè)表中將會(huì)存儲(chǔ)所有可用服務(wù)節(jié)點(diǎn)的信息捻勉,服務(wù)節(jié)點(diǎn)的信息可以在界面中直觀的看到
- Eureka Client是一個(gè)java客戶端镀梭,用于簡(jiǎn)化與Eureka Server的交互,客戶端同時(shí)也就是一個(gè)內(nèi)置的踱启、使用輪詢(round-robin)負(fù)載算法的負(fù)載均衡器
在應(yīng)用啟動(dòng)后报账,將會(huì)向Eureka Server發(fā)送心跳,默認(rèn)周期為30秒埠偿,如果Eureka Server在多個(gè)心跳周期內(nèi)沒(méi)有接收到某個(gè)節(jié)點(diǎn)的心跳透罢,Eureka Server將會(huì)從服務(wù)注冊(cè)表中把這個(gè)服務(wù)節(jié)點(diǎn)移除(默認(rèn)90秒)。
Eureka Server之間通過(guò)復(fù)制的方式完成數(shù)據(jù)的同步冠蒋,Eureka還提供了客戶端緩存機(jī)制羽圃,即使所有的Eureka Server都掛掉,客戶端依然可以利用緩存中的信息消費(fèi)其他服務(wù)的API抖剿。
Eureka中的三個(gè)核心角色:
- 服務(wù)注冊(cè)中心:Eureka Server端统屈,提供服務(wù)注冊(cè)發(fā)現(xiàn)功能
- 服務(wù)提供者:Eureka Client端,向注冊(cè)中心注冊(cè)服務(wù)牙躺,對(duì)外提供Rest風(fēng)格服務(wù)
- 服務(wù)消費(fèi)者:Eureka Client端愁憔,從注冊(cè)中心發(fā)現(xiàn)服務(wù)
2.1 創(chuàng)建父工程
創(chuàng)建一個(gè)Maven父工程來(lái)管理依賴:
<packaging>pom</packaging>
<!--Spring Boot版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<!--Spring Cloud版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.2 創(chuàng)建eureka-server子工程
eureka-server本身就是一個(gè)微服務(wù)
eureka-server會(huì)把注冊(cè)來(lái)的服務(wù)信息保存在Map中
-
添加eureka-server的起步依賴:
<dependencies> <!--eureka-server的起步依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies>
-
創(chuàng)建啟動(dòng)類,并添加@EnableEurekaServer注解:
package com.lhp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; // 啟用EurekaServer @EnableEurekaServer @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
-
在application.yml中配置:
server: port: 7000 eureka: client: # 是否將自己注冊(cè)到eureka-server中 register-with-eureka: false # 是否從eureka-server中獲取服務(wù)信息 fetch-registry: false service-url: # eureka-server的注冊(cè)地址 defaultZone: http://localhost:7000/eureka server: # 每隔5秒檢查一次心跳孽拷,剔除沒(méi)有續(xù)約的失效服務(wù) eviction-interval-timer-in-ms: 5000 # 關(guān)閉自我保護(hù)機(jī)制吨掌;自我保護(hù)模式下不會(huì)剔除任何服務(wù)實(shí)例 enable-self-preservation: false spring: application: # 應(yīng)用名,會(huì)在eureka中作為serviceId name: eureka-server
啟動(dòng),瀏覽器訪問(wèn)查看:http://localhost:7000/
2.3 創(chuàng)建provider子工程
服務(wù)提供者注冊(cè)服務(wù)
服務(wù)在啟動(dòng)時(shí)膜宋,若檢測(cè)到有@EnableDiscoveryClient注解和配置信息窿侈,則會(huì)向注冊(cè)中心發(fā)起注冊(cè)請(qǐng)求,攜帶服務(wù)元數(shù)據(jù)信息(ip秋茫、port等)
服務(wù)注冊(cè)完后史简,服務(wù)提供者會(huì)維持一個(gè)心跳,保存服務(wù)處于存在狀態(tài)肛著,這個(gè)稱之為服務(wù)續(xù)約(renew)
當(dāng)服務(wù)正常關(guān)閉時(shí)會(huì)發(fā)送服務(wù)下線的REST請(qǐng)求給eureka-server圆兵,eureka-server接收到請(qǐng)求后將該服務(wù)置為下線狀態(tài)
-
添加eureka-client的起步依賴和web的起步依賴:
<dependencies> <!--lombok的依賴--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--mybatis的起步依賴--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!--mybatis驅(qū)動(dòng)--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--需要添加web的起步依賴,不然client可能注冊(cè)不到eureka--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--eureka-client的起步依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
-
創(chuàng)建啟動(dòng)類枢贿,并添加@EnableDiscoveryClient注解或@EnableEurekaClient注解:
package com.lhp; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; // @EnableDiscoveryClient和@EnableEurekaClient任選其一即可 // 開(kāi)啟客戶端的發(fā)現(xiàn)功能殉农,且注冊(cè)中心只能是Eureka // @EnableEurekaClient // 開(kāi)啟客戶端的發(fā)現(xiàn)功能 @EnableDiscoveryClient // MapperScan會(huì)掃描指定包下的所有的接口,然后將接口的代理對(duì)象交給Spring容器 @MapperScan(basePackages = "com.lhp.dao") @SpringBootApplication public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
-
在application.yml中配置:
server: port: 7101 eureka: client: service-url: # eureka-server的注冊(cè)地址 defaultZone: http://localhost:7000/eureka # 獲取eureka-server中的服務(wù)列表(只讀備份)的間隔時(shí)間 registry-fetch-interval-seconds: 30 instance: # 指定自己的ip ip-address: 127.0.0.1 # 啟用ip進(jìn)行注冊(cè)局荚,而不是hostname prefer-ip-address: true # 租約過(guò)期時(shí)間超凳,默認(rèn)90seconds lease-expiration-duration-in-seconds: 150 # 租期續(xù)約間隔,默認(rèn)30seconds耀态;服務(wù)超過(guò)30秒沒(méi)有發(fā)生心跳轮傍,eureka-server會(huì)將服務(wù)從列表移除(前提是eureka-server關(guān)閉了自我保護(hù)) lease-renewal-interval-in-seconds: 30 spring: application: # 應(yīng)用名,會(huì)在eureka中作為serviceId name: provider datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/db01?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8 username: root password: 123456 mybatis: # 配置mybatis映射文件的位置 mapper-locations: classpath:com/lhp/dao/*Dao.xml
啟動(dòng)首装,瀏覽器訪問(wèn)查看:http://localhost:7000/
2.4 創(chuàng)建consumer子工程
服務(wù)消費(fèi)者發(fā)現(xiàn)服務(wù)
服務(wù)消費(fèi)者啟動(dòng)時(shí)创夜,會(huì)檢測(cè)是否獲取服務(wù)注冊(cè)信息配置;如果是簿盅,則會(huì)從eureka-server服務(wù)列表獲取只讀的備份挥下,緩存到本地
-
添加eureka-client的起步依賴和web的起步依賴:
<dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--需要添加web的起步依賴,不然client可能注冊(cè)不到eureka--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--eureka-client的起步依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
-
創(chuàng)建啟動(dòng)類桨醋,并添加@EnableDiscoveryClient注解或@EnableEurekaClient注解:
package com.lhp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; // 開(kāi)啟客戶端的發(fā)現(xiàn)功能 @EnableDiscoveryClient @SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } // 將RestTemplate對(duì)象放入到Spring容器 @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
-
在application.yml中配置:
server: port: 7201 eureka: client: service-url: # eureka-server的注冊(cè)地址 defaultZone: http://localhost:7000/eureka # 獲取eureka-server中的服務(wù)列表(只讀備份)的間隔時(shí)間 registry-fetch-interval-seconds: 30 spring: application: # 應(yīng)用名棚瘟,會(huì)在eureka中作為serviceId name: consumer
啟動(dòng),瀏覽器訪問(wèn)查看:http://localhost:7000/
2.5 consumer通過(guò)eureka-server訪問(wèn)provider
consumer在eureka-server中獲取provider的ip和port:
package com.lhp.controller;
import com.lhp.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/movie")
public class MovieController {
// RestTemplate是從Spring3.0開(kāi)始支持的一個(gè)HTTP請(qǐng)求工具喜最,它提供了常見(jiàn)的REST請(qǐng)求方案的模版
@Autowired
private RestTemplate restTemplate;
// DiscoveryClient可以發(fā)現(xiàn)當(dāng)前注冊(cè)中心的服務(wù)
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/see")
public Object see() {
// 獲取指定serviceId的實(shí)例集合
List<ServiceInstance> instances = discoveryClient.getInstances("provider");
// 獲取第0個(gè)實(shí)例
ServiceInstance instance = instances.get(0);
// 獲取實(shí)例的ip和port
String instanceUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/user/1";
// http://192.168.219.224:7001/user/1
System.out.println(instanceUrl);
User user = restTemplate.getForObject(instanceUrl, User.class);
return user;
}
}
3. Spring Cloud Netflix Ribbon
Ribbon是客戶端負(fù)載均衡器偎蘸,其負(fù)載均衡策略有(IRule實(shí)現(xiàn)類):
- com.netflix.loadbalancer.RoundRobinRule:輪詢
- com.netflix.loadbalancer.AvailabilityFilteringRule:根據(jù)可用性篩選
- com.netflix.loadbalancer.WeightedResponseTimeRule:根據(jù)加權(quán)響應(yīng)時(shí)間篩選
- com.netflix.loadbalancer.ZoneAvoidanceRule(默認(rèn)):根據(jù)區(qū)域和可用性篩選,使用區(qū)域(Zone)對(duì)服務(wù)器進(jìn)行分類
- com.netflix.loadbalancer.BestAvailableRule:忽略“短路”的服務(wù)器瞬内,并選擇并發(fā)數(shù)較低的服務(wù)器
- com.netflix.loadbalancer.RandomRule:隨機(jī)
- com.netflix.loadbalancer.RetryRule:重試
Ribbon使用:提前準(zhǔn)備一個(gè)服務(wù)集群(將provider復(fù)制一份充當(dāng)provider2迷雪,模擬時(shí)修改端口號(hào))
-
Eureka的依賴中已經(jīng)有了Ribbon的依賴,因此無(wú)需再引入依賴虫蝶;使用Ribbon時(shí)章咧,只需在RestTemplate的@Bean方法上添加@LoadBalanced注解
package com.lhp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; // 開(kāi)啟客戶端的發(fā)現(xiàn)功能 @EnableDiscoveryClient @SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } // 開(kāi)啟負(fù)載均衡 @LoadBalanced // 將RestTemplate對(duì)象放入到Spring容器 @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
-
consumer通過(guò)serviceId訪問(wèn)provider
package com.lhp.controller; import com.lhp.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.List; @RestController @RequestMapping("/movie") public class MovieController { // RestTemplate是從Spring3.0開(kāi)始支持的一個(gè)HTTP請(qǐng)求工具,它提供了常見(jiàn)的REST請(qǐng)求方案的模版 @Autowired private RestTemplate restTemplate; @GetMapping("/see") public Object see() { // 通過(guò)serviceId訪問(wèn)provider String serviceId = "provider"; String instanceUrl = "http://" + serviceId + "/user/1"; User user = restTemplate.getForObject(instanceUrl, User.class); return user; } }
-
修改對(duì)serviceId的負(fù)載均衡策略:
server: port: 7201 eureka: client: service-url: # eureka-server的注冊(cè)地址 defaultZone: http://localhost:7000/eureka # 獲取eureka-server中的服務(wù)列表(只讀備份)的間隔時(shí)間 registry-fetch-interval-seconds: 30 spring: application: # 應(yīng)用名能真,會(huì)在eureka中作為serviceId name: consumer # 修改對(duì)serviceId的負(fù)載均衡策略赁严,默認(rèn)是輪詢 # 格式:serviceId或default.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.類 # 若為default扰柠,則對(duì)所有服務(wù)生效 provider: ribbon: # 隨機(jī)策略 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
負(fù)載均衡的過(guò)程:
跟蹤LoadBalancerInterceptor類的源碼:LoadBalancerInterceptor會(huì)對(duì)RestTemplate的請(qǐng)求進(jìn)行攔截
ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution)
// 獲取服務(wù)名
String serviceName = originalUri.getHost()
<T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
// 獲取負(fù)載均衡器,此時(shí)負(fù)載均衡器中有serviceId的服務(wù)列表
ILoadBalancer loadBalancer = getLoadBalancer(serviceId)
// 根據(jù)負(fù)載均衡器選擇出要使用的服務(wù)節(jié)點(diǎn)
Server server = getServer(loadBalancer, hint)
4. Spring Cloud Netflix Hystrix
服務(wù)雪崩效應(yīng)是一種因“服務(wù)提供者”不可用而導(dǎo)致“服務(wù)消費(fèi)者”不可用疼约,并將不可用逐漸放大的過(guò)程卤档;在微服務(wù)中,一個(gè)請(qǐng)求可能需要多個(gè)微服務(wù)才能實(shí)現(xiàn)程剥,會(huì)形成復(fù)雜的調(diào)用鏈路劝枣,若鏈路中的某個(gè)基礎(chǔ)服務(wù)故障,則會(huì)導(dǎo)致級(jí)聯(lián)故障织鲸,進(jìn)而造成整個(gè)系統(tǒng)不可用
熔斷機(jī)制是應(yīng)對(duì)服務(wù)雪崩效應(yīng)的一種微服務(wù)鏈路保護(hù)機(jī)制舔腾,熔斷器有3個(gè)狀態(tài):
- Closed:所有請(qǐng)求正常訪問(wèn);當(dāng)失敗的請(qǐng)求量達(dá)到閾值(默認(rèn)20)昙沦,且失敗的請(qǐng)求百分比達(dá)到閾值(默認(rèn)50%)時(shí)琢唾,熔斷器從Closed切換到Open
- Open:請(qǐng)求會(huì)直接失敗而不會(huì)發(fā)送給服務(wù)载荔;Open保持一段時(shí)間后(默認(rèn)5秒)會(huì)自動(dòng)切換到Half Open
- Half Open:判斷下一次請(qǐng)求的返回情況盾饮,如果請(qǐng)求成功,則熔斷器切換到Closed懒熙,否則切換到Open
Hystrix解決服務(wù)雪崩效應(yīng)的主要方式:
- 服務(wù)降級(jí):當(dāng)某個(gè)服務(wù)熔斷之后將不再被調(diào)用丘损,此時(shí)客戶端可以自己準(zhǔn)備一個(gè)本地的fallback回調(diào),返回一個(gè)缺省值工扎,這樣雖然服務(wù)水平下降徘钥,但好歹可用,比直接掛掉要強(qiáng)
- 線程隔離:為每個(gè)服務(wù)分配一個(gè)小的線程池肢娘,如果一個(gè)服務(wù)的線程發(fā)生阻塞呈础,調(diào)用該服務(wù)的過(guò)程中不會(huì)影響到其它服務(wù)
Hystrix使用:
-
在consumer中添加hystrix的起步依賴
<!--hystrix的起步依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
在consumer的啟動(dòng)類上添加@EnableCircuitBreaker注解
-
在consumer的Controller中添加服務(wù)降級(jí)處理方法
// 服務(wù)降級(jí)處理方法,方法名隨意橱健,返回值和形參需要和@HystrixCommand修飾的方法一致 public Object fallback() { User user = new User(); user.setUsername("服務(wù)降級(jí)而钞,默認(rèn)處理!"); return user; }
-
局部熔斷:在consumer中可能發(fā)生問(wèn)題的方法上添加@HystrixCommand(fallbackMethod = "降級(jí)處理方法名")注解
// 如果方法發(fā)生問(wèn)題拘荡,則調(diào)用降級(jí)處理方法臼节;僅對(duì)當(dāng)前方法生效 @HystrixCommand(fallbackMethod = "fallback") @GetMapping("/see") public Object see() { // 通過(guò)serviceId訪問(wèn)provider String serviceId = "provider"; String instanceUrl = "http://" + serviceId + "/user/1"; User user = restTemplate.getForObject(instanceUrl, User.class); return user; }
-
全局熔斷:在consumer中可能發(fā)生問(wèn)題的方法上添加@HystrixCommand注解,并在類上添加@DefaultProperties(defaultFallback = "全局降級(jí)處理方法名")
package com.lhp.controller; import com.lhp.pojo.User; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; // 全局服務(wù)降級(jí)處理珊皿,對(duì)類的所有方法生效 @DefaultProperties(defaultFallback = "defaultFallback") @RestController @RequestMapping("/movie") public class MovieController { // RestTemplate是從Spring3.0開(kāi)始支持的一個(gè)HTTP請(qǐng)求工具网缝,它提供了常見(jiàn)的REST請(qǐng)求方案的模版 @Autowired private RestTemplate restTemplate; // 如果方法發(fā)生問(wèn)題,則調(diào)用降級(jí)處理方法蟋定;僅對(duì)當(dāng)前方法生效 // @HystrixCommand(fallbackMethod = "fallback") @HystrixCommand @GetMapping("/see") public Object see() { // 通過(guò)serviceId訪問(wèn)provider String serviceId = "provider"; String instanceUrl = "http://" + serviceId + "/user/1"; User user = restTemplate.getForObject(instanceUrl, User.class); return user; } // 全局服務(wù)降級(jí)處理方法:不能有形參粉臊,返回值應(yīng)與類中每個(gè)方法的返回值兼容 public Object defaultFallback() { User user = new User(); user.setUsername("服務(wù)降級(jí),全局默認(rèn)處理驶兜!"); return user; } // 服務(wù)降級(jí)處理方法扼仲,方法名隨意果元,返回值和形參需要和@HystrixCommand修飾的方法一致 public Object fallback() { User user = new User(); user.setUsername("服務(wù)降級(jí),默認(rèn)處理犀盟!"); return user; } }
-
在consumer的application.yml中追加其他熔斷策略的配置
# 配置熔斷策略 hystrix: command: default: circuitBreaker: # 是否強(qiáng)制打開(kāi)熔斷器 forceOpen: false # 失敗的請(qǐng)求量閾值 requestVolumeThreshold: 10 # 失敗的請(qǐng)求百分比閾值 errorThresholdPercentage: 50 # Open到Half Open的時(shí)間 sleepWindowInMilliseconds: 10000 execution: isolation: thread: # 熔斷超時(shí)時(shí)間 timeoutInMilliseconds: 2000
5. Spring Cloud OpenFeign
OpenFeign是一個(gè)聲明性的REST客戶端
OpenFeign已經(jīng)集成了Ribbon而晒、Hystrix、slf4j
使用OpenFeign替代RestTemplate發(fā)送Rest請(qǐng)求:
-
在consumer中添加openfeign的起步依賴:
<!--openfeign的起步依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
在consumer的啟動(dòng)類上添加@EnableFeignClients注解
-
在consumer中創(chuàng)建POJOFeign接口
package com.lhp.feign; import com.lhp.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; /** * Feign會(huì)通過(guò)動(dòng)態(tài)代理生成實(shí)現(xiàn)類 * FeignClient(name = "serviceId")注解聲明該接口是一個(gè)Feign的客戶端 */ @FeignClient(name = "provider") @RequestMapping("/user") public interface UserFeign { /** * Feign會(huì)根據(jù)注解生成URL地址 * 方法名隨意 * 返回值和形參應(yīng)和provider中的保持一致 */ @GetMapping("/{id}") User findById(@PathVariable(name = "id") Integer id); }
-
在consumer的Controller中注入并使用POJOFeign:
package com.lhp.controller; import com.lhp.feign.UserFeign; import com.lhp.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/feign") public class ConsumerController { @Autowired private UserFeign userFeign; // 使用Feign調(diào)用provider的方法 @RequestMapping("/{id}") public User findById(@PathVariable(value = "id") Integer id) { return userFeign.findById(id); } }
瀏覽器訪問(wèn)測(cè)試:http://localhost:7201/feign/1
5.1 OpenFeign配置Ribbon
在consumer的application.yml中配置ribbon:
provider:
ribbon:
# 負(fù)載均衡策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# 連接超時(shí)時(shí)間
ConnectTimeout: 10000
# 請(qǐng)求處理超時(shí)時(shí)間
ReadTimeout: 2000
# 最大重試次數(shù)
MaxAutoRetries: 1
# 重試集群中下一個(gè)服務(wù)實(shí)例的最大次數(shù)
MaxAutoRetriesNextServer: 0
# 所有操作都重試
OkToRetryOnAllOperations: false
5.2 OpenFeign配置Hystrix
-
在consumer的application.yml中啟用feign的hystrix:
feign: hystrix: # 啟用feign的hystrix enabled: true
-
實(shí)現(xiàn)POJOFeign接口
package com.lhp.feign.impl; import com.lhp.feign.UserFeign; import com.lhp.pojo.User; import org.springframework.stereotype.Component; /** * 重寫的每一個(gè)方法阅畴,即這個(gè)方法的降級(jí)處理方法 */ @Component public class UserFeignImpl implements UserFeign { @Override public User findById(Integer id) { User user = new User(); user.setUsername("feign的hystrix:降級(jí)處理方法"); return user; } }
-
在consumer中POJOFeign接口的@FeignClient注解中指定降級(jí)處理類倡怎,并去掉接口上的@RequestMapping注解
package com.lhp.feign; import com.lhp.feign.impl.UserFeignImpl; import com.lhp.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; /** * Feign會(huì)通過(guò)動(dòng)態(tài)代理生成實(shí)現(xiàn)類 * FeignClient(name = "serviceId")注解聲明該接口是一個(gè)Feign的客戶端 * fallback指定降級(jí)處理類 */ @FeignClient(name = "provider", fallback = UserFeignImpl.class, path = "/user") // 若用服務(wù)降級(jí),則不能在接口上使用@RequestMapping注解贱枣;要么在@FeignClient中配置path屬性监署,要么在方法上拼接全路徑 // @RequestMapping("/user") public interface UserFeign { /** * Feign會(huì)根據(jù)注解生成URL地址 * 方法名隨意 * 返回值和形參應(yīng)和provider中的保持一致 */ @GetMapping("/{id}") User findById(@PathVariable(name = "id") Integer id); }
5.3 配置請(qǐng)求/響應(yīng)壓縮
OpenFeign可以對(duì)請(qǐng)求和響應(yīng)進(jìn)行GZIP壓縮,以減少通信過(guò)程中的性能損耗
在consumer的application.yml中啟用feign的請(qǐng)求壓縮:
feign:
compression:
# 請(qǐng)求壓縮
request:
enabled: true
# 對(duì)指定類型的數(shù)據(jù)進(jìn)行壓縮
mime-types: text/html,application/xml,application/json
# 觸發(fā)壓縮的下限
min-request-size: 2048
# 響應(yīng)壓縮
response:
enabled: true
5.4 配置日志
OpenFeign配置日志:
-
在consumer的application.yml中配置普通日志級(jí)別
# com.lhp包下的日志級(jí)別都為debug logging: level: com.lhp: debug
-
在一個(gè)配置類中注入Logger.Level
package com.lhp.feign.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignLogger { @Bean public Logger.Level feignLoggerLevel() { /** * NONE:不記錄任何日志纽哥,默認(rèn)值 * BASIC:僅記錄請(qǐng)求的方法钠乏、URL、狀態(tài)碼春塌、執(zhí)行時(shí)間 * HEADERS:在BASIC基礎(chǔ)上記錄了請(qǐng)求和響應(yīng)的頭信息 * FULL:記錄所有請(qǐng)求和響應(yīng)的明細(xì) */ return Logger.Level.FULL; } }
-
在consumer中POJOFeign接口的@FeignClient注解中指定配置類
@FeignClient(name = "provider", fallback = UserFeignImpl.class, path = "/user", configuration = FeignLogger.class)
6. Spring Cloud Gateway
Spring Cloud Gateway旨在提供一種簡(jiǎn)單而有效的方式來(lái)路由API
網(wǎng)關(guān)可以根據(jù)斷言的規(guī)則對(duì)請(qǐng)求進(jìn)行轉(zhuǎn)發(fā)(路由)晓避、過(guò)濾
6.1 Gateway基本使用
環(huán)境準(zhǔn)備:Gateway本身就是一個(gè)微服務(wù),先創(chuàng)建一個(gè)子工程Eureka Client端
-
創(chuàng)建gateway子工程只壳,添加gateway的起步依賴(不要加入web的起步依賴俏拱,沖突):
<dependencies> <!--gateway起步依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--eureka-client起步依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
-
創(chuàng)建啟動(dòng)類
package com.lhp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; // 開(kāi)啟客戶端的發(fā)現(xiàn)功能 @EnableDiscoveryClient @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
-
在application.yml中配置路由規(guī)則:
server: port: 7301 eureka: client: service-url: defaultZone: http://localhost:7000/eureka spring: application: name: gateway cloud: gateway: # 配置路由規(guī)則 routes: - id: user-service-route # 路由id # 轉(zhuǎn)發(fā)到哪個(gè)uri # uri: http://localhost:7101 # lb協(xié)議表示從eureka-server獲取服務(wù)請(qǐng)求地址,并且會(huì)通過(guò)Ribbon進(jìn)行負(fù)載均衡 uri: lb://provider # 斷言:路由攔截的地址 predicates: # 如:http://localhost:7301/user/1--轉(zhuǎn)發(fā)到-->http://localhost:7101/user/1 - Path=/user/** # 將以/user/開(kāi)頭的請(qǐng)求都轉(zhuǎn)發(fā)到uri # 配置局部過(guò)濾器 filters: # Param需要自定義ParamGatewayFilterFactory類 #- Param=age, 21 # 以下兩個(gè)規(guī)則相互抵消了 # PrefixPath給請(qǐng)求添加前綴吼句,自帶的 # 如:http://localhost:7301/1--轉(zhuǎn)發(fā)到-->http://localhost:7101/user/1 - PrefixPath=/user # StripPrefix給請(qǐng)求去除前綴锅必,自帶的 # 如去除第1個(gè)前綴:http://localhost:7301/user/1--轉(zhuǎn)發(fā)到-->http://localhost:7101/1 - StripPrefix=1 # 配置全局默認(rèn)過(guò)濾器 default-filters: - AddResponseHeader=MyName, lhp # 添加響應(yīng)頭:字段名, 值
6.2 過(guò)濾器
過(guò)濾器分類:
- 全局過(guò)濾器:作用在所有路由上
- 局部過(guò)濾器:只作用在具體路由上
- 默認(rèn)過(guò)濾器
- 自定義過(guò)濾器
常見(jiàn)默認(rèn)過(guò)濾器:
- AddRequestHeader:添加請(qǐng)求頭
- AddRequestParameter:添加請(qǐng)求參數(shù)
- AddResponseHeader:添加響應(yīng)頭
- StripPrefix:去除前綴
自定義全局過(guò)濾器:創(chuàng)建GlobalFilter實(shí)現(xiàn)類,并交給Spring容器
package com.lhp.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class LoginGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 獲取請(qǐng)求參數(shù)
String token = exchange.getRequest().getQueryParams().getFirst("token");
// 如果token為空惕艳,則沒(méi)登錄
if (StringUtils.isEmpty(token)) {
// 設(shè)置狀態(tài)碼為403
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
// 結(jié)束請(qǐng)求
return exchange.getResponse().setComplete();
}
// 放行
return chain.filter(exchange);
// 帶token訪問(wèn)測(cè)試:http://localhost:7301/user/1?token=1
// 不帶token訪問(wèn)測(cè)試:http://localhost:7301/user/1
}
// 定義過(guò)濾器執(zhí)行順序搞隐;返回值越小,優(yōu)先級(jí)越高
@Override
public int getOrder() {
return 0;
}
}
自定義局部過(guò)濾器:創(chuàng)建AbstractNameValueGatewayFilterFactory子類远搪,并交給Spring容器
package com.lhp.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
// XxxGatewayFilterFactory:Xxx為yaml配置文件中filters的參數(shù)
// 需要在yaml配置文件中的filters添加:- Param=name, value
@Component
public class ParamGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 獲取yaml配置文件中filters的- Param=name, value
System.out.println("nameInConfig=" + config.getName() + ", " + "valueInConfig=" + config.getValue());
// 放行
return chain.filter(exchange);
}
};
}
}
7. Spring Cloud Config
創(chuàng)建一個(gè)遠(yuǎn)程倉(cāng)庫(kù)劣纲,在其中創(chuàng)建需要被統(tǒng)一配置管理的配置文件
配置文件命名規(guī)約:${application}-${profile}.yml/yaml/properties
${application}為應(yīng)用名稱
${profile}用于區(qū)分開(kāi)發(fā)環(huán)境dev、測(cè)試環(huán)境test终娃、生產(chǎn)環(huán)境pro等
例如:將provider的application.yml重命名為provider-dev.yml上傳到遠(yuǎn)程倉(cāng)庫(kù)
創(chuàng)建配置中心config-server子工程:
-
添加config-server的依賴:
<dependencies> <!--eureka-client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--config-server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> </dependencies>
-
在啟動(dòng)類上添加@EnableConfigServer注解:
package com.lhp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; // 開(kāi)啟配置服務(wù)功能 @EnableConfigServer // 開(kāi)啟客戶端的發(fā)現(xiàn)功能 @EnableDiscoveryClient @SpringBootApplication public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
-
在application.yml中配置:
server: port: 7401 eureka: client: service-url: # eureka-server的注冊(cè)地址 defaultZone: http://localhost:7000/eureka spring: application: name: config-server cloud: config: server: git: # 遠(yuǎn)程倉(cāng)庫(kù)的地址 uri: https://gitee.com/liu-haopeng/config.git # com包下的日志級(jí)別都為debug logging: level: com: debug
啟動(dòng)味廊,瀏覽器訪問(wèn)查看文件:http://localhost:7401/provider-dev.yml
讓provider從配置中心獲取配置:
-
添加config的起步依賴:
<!--config的起步依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
-
刪除原來(lái)的application.yml,創(chuàng)建bootstrap.yml:
# bootstrap.yml是SpringBoot的默認(rèn)配置文件棠耕,其加載時(shí)間早于application.yml # bootstrap.yml一般用于系統(tǒng)級(jí)配置余佛,而application.yml一般用于應(yīng)用級(jí)配置 eureka: client: service-url: # eureka-server的注冊(cè)地址 defaultZone: http://localhost:7000/eureka spring: cloud: config: name: provider # 遠(yuǎn)程倉(cāng)庫(kù)中配置文件名的{application} profile: dev # 遠(yuǎn)程倉(cāng)庫(kù)中配置文件名的{profile} label: master # 遠(yuǎn)程倉(cāng)庫(kù)的分支 discovery: # 啟用配置中心 enabled: true # 配置中心的serviceId service-id: config-server
依次啟動(dòng)eureka-server、config-server窍荧、provider辉巡,看provider是否報(bào)錯(cuò)
以上存在的問(wèn)題:若修改遠(yuǎn)程倉(cāng)庫(kù)中的配置,config-server立即生效蕊退,而provider只有重啟后才會(huì)生效
8. Spring Cloud Bus
Spring Cloud Bus可以解決Spring Cloud Config修改遠(yuǎn)程倉(cāng)庫(kù)中的配置后郊楣,服務(wù)只有重啟后才會(huì)生效的問(wèn)題
Spring Cloud Bus默認(rèn)基于RabbitMQ憔恳,因此使用Spring Cloud Bus前需要先啟動(dòng)RabbitMQ
消息總線分發(fā)消息的過(guò)程:
- 訪問(wèn)配置中心的消息總線
- 消息總線接收到請(qǐng)求后向消息隊(duì)列發(fā)送消息
- provider微服務(wù)監(jiān)聽(tīng)到消息隊(duì)列中的消息后會(huì)重新從配置中心獲取最新配置信息
修改config-server子工程:
-
添加bus和stream-binder-rabbit的依賴:
<!--bus--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-bus</artifactId> </dependency> <!--stream-binder-rabbit--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> </dependency>
-
在application.yml中配置RabbitMQ并開(kāi)放bus-refresh接口:
server: port: 7401 eureka: client: service-url: # eureka-server的注冊(cè)地址 defaultZone: http://localhost:7000/eureka spring: application: name: config-server cloud: config: server: git: # 遠(yuǎn)程倉(cāng)庫(kù)的地址 uri: https://gitee.com/liu-haopeng/config.git # 配置RabbitMQ rabbitmq: host: localhost port: 5672 virtual-host: / username: guest password: guest management: endpoints: web: exposure: # 開(kāi)放bus-refresh接口,以便配合bus實(shí)現(xiàn)配置動(dòng)態(tài)刷新 include: bus-refresh # com包下的日志級(jí)別都為debug logging: level: com: debug
修改provider子工程:
-
添加bus和stream-binder-rabbit的依賴:
<!--bus--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-bus</artifactId> </dependency> <!--stream-binder-rabbit--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> </dependency>
-
在bootstrap.yml中配置RabbitMQ:
# bootstrap.yml是SpringBoot的默認(rèn)配置文件净蚤,其加載時(shí)間早于application.yml # bootstrap.yml一般用于系統(tǒng)級(jí)配置钥组,而application.yml一般用于應(yīng)用級(jí)配置 eureka: client: service-url: # eureka-server的注冊(cè)地址 defaultZone: http://localhost:7000/eureka spring: cloud: config: name: provider # 遠(yuǎn)程倉(cāng)庫(kù)中配置文件名的{application} profile: dev # 遠(yuǎn)程倉(cāng)庫(kù)中配置文件名的{profile} label: master # 遠(yuǎn)程倉(cāng)庫(kù)的分支 discovery: # 啟用配置中心 enabled: true # 配置中心的serviceId service-id: config-server # 配置RabbitMQ rabbitmq: host: localhost port: 5672 virtual-host: / username: guest password: guest
-
@RefreshScope注解可以啟用刷新配置文件的信息:創(chuàng)建一個(gè)單獨(dú)的配置類存放yml中的數(shù)據(jù),然后在Controller中注入這個(gè)配置類今瀑,不然直接在Controller上添加@RefreshScope注解會(huì)導(dǎo)致獲取的配置為空
package com.lhp.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Component; // 啟用刷新配置文件的信息 @RefreshScope @Component public class ConfigData { @Value("${age}") private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
修改遠(yuǎn)程倉(cāng)庫(kù)中的配置后程梦,以POST方式訪問(wèn)配置中心的消息總線http://localhost:7401/actuator/bus-refresh,actuator固定橘荠,bus-refresh為配置中心yml中的management.endpoints.web.exposure.include
以上組件的Spring Cloud總架構(gòu)圖:
9. Spring Cloud Alibaba Nacos
Spring Cloud Alibaba的組件版本關(guān)系:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
Nacos官網(wǎng):https://nacos.io/zh-cn/
Nacos可以代替Eureka做注冊(cè)中心屿附,也可以代替Config做配置中心
Nacos支持CP和AP模式的切換:
- 一致性C:在分布式系統(tǒng)中的所有數(shù)據(jù)備份,在同一時(shí)刻是否同樣的值哥童。(等同于所有節(jié)點(diǎn)訪問(wèn)同一份最新的數(shù)據(jù)副本)
- 可用性A:在集群中一部分節(jié)點(diǎn)故障后挺份,集群整體是否還能響應(yīng)客戶端的讀寫請(qǐng)求。(對(duì)數(shù)據(jù)更新具備高可用性)
- 分區(qū)容忍性P:分區(qū)相當(dāng)于對(duì)通信的時(shí)限要求贮懈,系統(tǒng)如果不能在時(shí)限內(nèi)達(dá)成數(shù)據(jù)一致性匀泊,就意味著發(fā)生了分區(qū)的情況,必須就當(dāng)前操作在C和A之間做出選擇错邦。
- AP模式下只支持注冊(cè)臨時(shí)實(shí)例探赫,CP模式下支持注冊(cè)持久化實(shí)例
Nacos分為客戶端和服務(wù)端型宙,客戶端可以是個(gè)微服務(wù)撬呢,服務(wù)端需要單獨(dú)下載安裝:
- Nacos服務(wù)端下載(如:nacos-server-1.2.1.zip):https://github.com/alibaba/nacos/releases
- Nacos安裝啟動(dòng):解壓安裝包,Windows下啟動(dòng)bin目錄里的startup.cmd妆兑;Linux下執(zhí)行:
sh startup.sh -m standalone
- 啟動(dòng)后瀏覽器訪問(wèn)魂拦,默認(rèn)賬號(hào)和密碼都是nacos:http://localhost:8848/nacos
9.1 創(chuàng)建父工程
創(chuàng)建一個(gè)Maven父工程來(lái)管理依賴:
<packaging>pom</packaging>
<!--Spring Boot版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<!--Spring Cloud版本-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring Cloud Alibaba版本-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
9.2 Nacos作為注冊(cè)中心
-
創(chuàng)建nacos-client子工程,導(dǎo)入依賴
<dependencies> <!--nacos作為注冊(cè)中心客戶端的起步依賴--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--web起步依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
-
創(chuàng)建啟動(dòng)類搁嗓,并添加@EnableDiscoveryClient注解
package com.lhp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class NacosClientApplication { public static void main(String[] args) { SpringApplication.run(NacosClientApplication.class, args); } }
-
在application.yml中配置:
server: port: 9001 spring: application: name: nacos-client
-
在bootstrap.yml中配置:
spring: cloud: nacos: # 服務(wù)端地址 server-addr: localhost:8848 discovery: # 服務(wù)端的注冊(cè)地址 server-addr: ${spring.cloud.nacos.server-addr} application: name: nacos-client
啟動(dòng)服務(wù)端和客戶端微服務(wù)芯勘,瀏覽器訪問(wèn)服務(wù)端查看:http://localhost:8848/nacos
9.2 Nacos作為配置中心
-
導(dǎo)入依賴:
<!--nacos作為配置中心的起步依賴--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
在application.yml中配置:
server: port: 9001 spring: application: name: nacos-client
-
在bootstrap.yml中配置spring.cloud.nacos.config:
spring: cloud: nacos: # 服務(wù)端地址 server-addr: localhost:8848 discovery: # 服務(wù)端的注冊(cè)地址 server-addr: ${spring.cloud.nacos.server-addr} config: # 配置中心的地址 server-addr: ${spring.cloud.nacos.server-addr} # 配置文件的配置格式,默認(rèn)為properties file-extension: yaml # 命名空間ID namespace: public # Group group: DEFAULT_GROUP application: name: nacos-client
-
進(jìn)入Nacos服務(wù)端的配置管理-->配置列表-->點(diǎn)擊+號(hào)新建配置
Data ID格式:${prefix}-${spring.profile.active}.${file-extension} prefix默認(rèn)為:spring.application.name腺逛,也可以通過(guò)spring.cloud.nacos.config.prefix來(lái)配置 spring.profile.active為空時(shí)的格式:${prefix}.${file-extension} 例如:nacos-client.yaml 配置格式:選擇配置文件的格式 配置內(nèi)容:application.yml的內(nèi)容
Nacos有不同的管理級(jí)別荷愕,可以進(jìn)行多環(huán)境管理:
- 配置集Data Id:一個(gè)配置文件通常就是一個(gè)配置集,配置文件中的每一項(xiàng)是配置項(xiàng)
- 配置分組group:配置分組是對(duì)配置集進(jìn)行分組
- 命名空間namespace:可用于進(jìn)行不同環(huán)境的配置隔離
- 范圍大泄髅: