Spring Cloud Demo
本文介紹Spring Cloud 常用的組件的demo代碼。gitee代碼:https://gitee.com/Aes_yt/spring-cloud-demo
包括Spring Cloud Eureka,Spring Cloud Feign,Spring Cloud Hystrix,Spring Cloud Ribbon,Spring Cloud Zuul,Spring Cloud Config,Spring Cloud Sleuth。
Spring Cloud Eureka
Server
-
pom引入:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
-
代碼:
SpringBootApplication 啟動(dòng)類(lèi)加入
@EnableEurekaServer
注解。 -
配置:
server: port: 8761 eureka: instance: hostname: localhost client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ server: wait-time-in-ms-when-sync-empty: 0 enable-self-preservation: false
Client
-
pom引入:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
-
代碼:
SpringBootApplication 啟動(dòng)類(lèi)加入
@EnableDiscoveryClient
注解。 -
配置:
server: port: 8081 spring: application: name: demo-client1 eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
TIPS. 非java語(yǔ)言也可使用Eureka提供的REST API接口接入Server。 wiki
常見(jiàn)問(wèn)題
-
為什么服務(wù)上線(xiàn)了,Eureka Client 不能及時(shí)獲取到。
Eureka Server 的 REST API 有response cache,需要等緩存過(guò)期后才能更新數(shù)據(jù)。
-
為什么服務(wù)下線(xiàn)了,Eureka Server 接口返回的信息還會(huì)存在。
應(yīng)用實(shí)例異常掛掉,沒(méi)有在掛掉之前告知Server 要下線(xiàn)。這個(gè)就需要依賴(lài)Eureka Server的EvictionTask 去剔除。
-
其他:
springcloud對(duì)springboot的版本是有要求的,如果不一致,會(huì)啟動(dòng)不起來(lái)的。詳細(xì)可以看官網(wǎng)的版本要求。
Spring Cloud Feign + Spring Cloud Hystrix
demo-hello
-
首先先創(chuàng)建一個(gè) demo 的 module,接入Eureka配置(eureka-client )。設(shè)置端口8082,里面只有一個(gè)get方法,我們用postman調(diào)用 http://localhost:8082/hello/testGet?param=hello,能夠正常返回。
@RestController @RequestMapping("/hello") @Slf4j public class HelloController { @GetMapping("/testGet") public BaseResp<String> testGet(@RequestParam("param") String param) { log.info("[demo-hello] testGet:{}", param); return BaseResp.success(param); } }
yml:
server: port: 8082 spring: application: name: demo-hello eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
feign-client
-
創(chuàng)建一個(gè)新module。引入Eureka-client依賴(lài),feign依賴(lài)和hystrix依賴(lài)。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- cloud 2020.0.x 之后無(wú)此依賴(lài) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
注意:hystrix 在 spring-cloud 2020.0.x 版本廢棄,之后的版本推薦使用 Resilience4j 進(jìn)行服務(wù)的熔斷。
-
yaml 配置
server: port: 8083 spring: application: name: feign-client eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ feign: # hystrix熔斷開(kāi)關(guān) hystrix: enabled: true # feign-client的超時(shí)時(shí)間 client: config: default: connect-timeout: 3000 read-timeout: 3000 logger-level: basic # 設(shè)置hystrix服務(wù)降級(jí)超時(shí)時(shí)間 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 15000
-
Application 注解
@EnableFeignClients:@EnableFeignClients 是一個(gè) Spring Cloud 注解,用于啟用 Feign 客戶(hù)端的功能。
@EnableCircuitBreaker:
@EnableCircuitBreaker
是 Spring Cloud 提供的一個(gè)注解,用于啟用熔斷器(Circuit Breaker)的功能。@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients @EnableCircuitBreaker public class FeignClientApplication { public static void main(String[] args) { SpringApplication.run(FeignClientApplication.class, args); } }
-
建立Feign調(diào)用Service
@FeignClient(name = "demo-hello", contextId = "feign-hello", path = "/hello", fallbackFactory = FeignHelloServiceHystrix.class) public interface FeignHelloService { @RequestMapping(value = "/testGet", method = RequestMethod.GET) BaseResp<String> testGet(@RequestParam("param") String param); }
name = "demo-hello" 就是 demo 項(xiàng)目的
spring.application.name
,contentxId 就相當(dāng)于這個(gè)調(diào)用service的唯一id,path就是統(tǒng)一前綴。fallbackFactory 就是降級(jí)后的工廠(chǎng)。所以我們要實(shí)現(xiàn)這個(gè)工廠(chǎng)。我這邊的邏輯,就是記錄一下日志,然后返回統(tǒng)一的錯(cuò)誤對(duì)象。
@Slf4j @Component public class FeignHelloServiceHystrix implements FallbackFactory<FeignHelloService> { @Override public FeignHelloService create(Throwable cause) { log.error("feign調(diào)用helloController報(bào)錯(cuò)", cause); return new FeignHelloService() { public BaseResp<String> testGet(String param) { return BaseResp.error(param); } }; } }
-
測(cè)試一下,
@GetMapping("/testGet") public BaseResp<String> testGet(@RequestParam("param") String param) { // try { // Thread.sleep(6000); // } catch (InterruptedException e) { // throw new RuntimeException(e); // } // if(!param.isEmpty()){ // throw new RuntimeException("error..."); // } log.info("[demo-hello] testGet:{}", param); return BaseResp.success(param); }
testGet 6秒鐘才響應(yīng)或者直接拋出異常,都是會(huì)進(jìn)入FeignHelloServiceHystrix中打印日志。
附加
-
Feign 加日志打印
-
xml配置Feign客戶(hù)端
# Feign 日志配置 logging: level: com.yt.demo.service.feign: debug
-
Feign 配置
/** * Feign 配置 */ @Slf4j @Configuration public class FeignConfig { /** * NONE:不記錄任何信息 * BASIC:僅記錄請(qǐng)求方法、URL以及響應(yīng)狀態(tài)碼和執(zhí)行時(shí)間. * HEADERS:除了記錄BASIC級(jí)別的信息外,還會(huì)記錄請(qǐng)求和響應(yīng)的頭信息 * FULL:記錄所有請(qǐng)求與響應(yīng)的明細(xì),包括頭信息、請(qǐng)求體、元數(shù)據(jù) */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
-
效果如下:
2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] ---> POST http://demo-hello/hello/testPost HTTP/1.1 2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] Content-Length: 30 2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] Content-Type: application/json 2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] 2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] {"param":"Post method: hello"} 2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] ---> END HTTP (30-byte body) 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] <--- HTTP/1.1 200 (2ms) 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] connection: keep-alive 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] content-type: application/json 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] date: Fri, 23 Jun 2023 03:38:43 GMT 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] keep-alive: timeout=60 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] transfer-encoding: chunked 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] {"code":200,"data":"Post method: hello","msg":"success"} 2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService : [FeignHelloService#testPost] <--- END HTTP (56-byte body)
-
-
文件上傳
-
feign Client 里面新增文件上傳方法
@RequestMapping(value = "/testFile", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) BaseResp<String> testFile(@RequestPart("file") MultipartFile file);
注意配置@RequestPart 注解,參數(shù)加上:
produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE
-
常見(jiàn)問(wèn)題
-
demo項(xiàng)目的方法返回報(bào)錯(cuò),或者超時(shí),都并沒(méi)有進(jìn)入熔斷工廠(chǎng)。
檢查一下feign-client的hystrix是否啟用:
feign.hystrix.enabled: true
-
配置了feign-client的超時(shí)時(shí)間為3s,demo返回時(shí)間6s,但是1s就馬上進(jìn)入熔斷工廠(chǎng)報(bào)超時(shí),并沒(méi)有等待3s。
feign-client的超時(shí)時(shí)間和hystrix的超時(shí)時(shí)間都要配置。
-
配置了超時(shí)時(shí)間,但是還是不生效。
根據(jù)你的cloud版本搜索一下,對(duì)應(yīng)的配置怎么配。有可能不同版本的配置方法不一樣,單詞改變了之類(lèi)的都是有可能的。
-
feign調(diào)用報(bào)錯(cuò):Load balancer does not have available server for client : xxx
feign客戶(hù)端的yaml配置加上
fetch-registry: true
eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ fetch-registry: true
Spring Cloud Ribbon
demo-hello
-
demo-hello 復(fù)用上面Feign的controller新增一個(gè)測(cè)試方法,打印出當(dāng)前服務(wù)器端口
@GetMapping("/testRibbon") public BaseResp<String> testRibbon(@RequestParam("param") String param, HttpServletRequest httpServletRequest) { log.info("接收到請(qǐng)求,參數(shù):{}, serverPort:{}", param, httpServletRequest.getServerPort()); return BaseResp.success("Response from server port: " + httpServletRequest.getServerPort()); }
-
啟動(dòng)項(xiàng)目,之后修改application.xml的端口號(hào)port,重新啟動(dòng)一個(gè)實(shí)例。
-
啟動(dòng)成功之后,在Eureka界面可以看到兩個(gè)啟動(dòng)的實(shí)例。
Application AMIs Availability Zones Status DEMO-HELLO n/a (2) (2) UP (2) - 192.168.0.101:demo-hello:8082 , 192.168.0.101:demo-hello:8084
ribbon-client
-
新建一個(gè)項(xiàng)目。[可以從Eureka-client復(fù)制,然后修改spring.application.name和pom文件的artifactId]。
-
引入ribbon依賴(lài)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
-
新建ribbon配置類(lèi),重點(diǎn)是用@LoadBalance注解來(lái)聲明restTemplate具有負(fù)載均衡能力。而且這樣在使用restTeamplate的時(shí)候就能通過(guò)eureka上面的服務(wù)名來(lái)調(diào)用服務(wù)了,
@Slf4j @Configuration public class RibbonConfig { @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
-
新建一個(gè)測(cè)試類(lèi),直接調(diào)用十次請(qǐng)求
@RestController @RequestMapping("/client") @Slf4j public class HelloController { @Autowired private RestTemplate restTemplate; @GetMapping("/testRibbon") public BaseResp<String> testRibbon(@RequestParam("param") String param) { String url = "http://demo-hello/hello/testRibbon?param=" + param; for (int i = 0; i < 10; i++) { BaseResp<?> resp = restTemplate.getForObject(url, BaseResp.class); log.info("i-{}: {}", i, resp); } return BaseResp.success(null); } }
-
返回結(jié)果:
2023-06-23 15:42:40.802 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-0: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:42:40.805 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-1: BaseResp(code=200, data=Response from server port: 8082, msg=success) 2023-06-23 15:42:40.807 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-2: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:42:40.810 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-3: BaseResp(code=200, data=Response from server port: 8082, msg=success) 2023-06-23 15:42:40.812 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-4: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:42:40.814 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-5: BaseResp(code=200, data=Response from server port: 8082, msg=success) 2023-06-23 15:42:40.818 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-6: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:42:40.820 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-7: BaseResp(code=200, data=Response from server port: 8082, msg=success) 2023-06-23 15:42:40.824 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-8: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:42:40.826 INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController : i-9: BaseResp(code=200, data=Response from server port: 8082, msg=success)
ribbon的默認(rèn)負(fù)載均衡策略是ZoneAvoidanceRule,可以看出請(qǐng)求分別調(diào)到了8084和8082兩個(gè)服務(wù)實(shí)例上。
-
負(fù)載均衡策略配置
-
Ribbon內(nèi)置的負(fù)載均衡規(guī)則:
規(guī)則名稱(chēng) 特點(diǎn) AvailabilityFilteringRule 過(guò)濾掉一直連接失敗的被標(biāo)記為circuit tripped的后端Server,并 過(guò)濾掉那些高并發(fā)的后端Server或者使用一個(gè)AvailabilityPredicate 來(lái)包含過(guò)濾server的邏輯,其實(shí)就是檢查status里記錄的各個(gè)server 的運(yùn)行狀態(tài) BestAvailableRule 選擇一個(gè)最小的并發(fā)請(qǐng)求的server,逐個(gè)考察server, 如果Server被tripped了,則跳過(guò) RandomRule 隨機(jī)選擇一個(gè)Server WeightedResponseTimeRule 根據(jù)響應(yīng)時(shí)間加權(quán),響應(yīng)時(shí)間越長(zhǎng),權(quán)重越小,被選中的可能性越低 RetryRule 對(duì)選定的負(fù)載均衡策略加上重試機(jī)制,在一個(gè)配置時(shí)間段內(nèi)當(dāng) 選擇Server不成功,則一直嘗試使用subRule的方式選擇一個(gè) 可用的Server RoundRobinRule 輪詢(xún)選擇,輪詢(xún)index,選擇index對(duì)應(yīng)位置的Server ZoneAvoidanceRule 復(fù)合判斷Server所在區(qū)域的性能和Server的可用性 選擇Server,在沒(méi)有區(qū)域的環(huán)境下,類(lèi)似于輪詢(xún)(RandomRule) -
修改策略為隨機(jī):
RibbonConfig.java 新增配置[全局]
/** * 配置輪詢(xún)策略為RandomRule * 其他的策略配置也一樣,策略類(lèi)路徑都是 com.netflix.loadbalancer.xxx */ @Bean public IRule ribbonRule(){ return new RandomRule(); }
或:按服務(wù)粒度進(jìn)行配置:(demo-hello 是目標(biāo)服務(wù)的服務(wù)名)
demo-hello: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
我直接配置全局的
ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
不生效,不知道是不是不支持全局配置。效果:
2023-06-23 15:59:31.095 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-0: BaseResp(code=200, data=Response from server port: 8082, msg=success) 2023-06-23 15:59:31.097 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-1: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:59:31.100 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-2: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:59:31.104 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-3: BaseResp(code=200, data=Response from server port: 8082, msg=success) 2023-06-23 15:59:31.108 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-4: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:59:31.112 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-5: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:59:31.117 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-6: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:59:31.124 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-7: BaseResp(code=200, data=Response from server port: 8082, msg=success) 2023-06-23 15:59:31.132 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-8: BaseResp(code=200, data=Response from server port: 8084, msg=success) 2023-06-23 15:59:31.137 INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController : i-9: BaseResp(code=200, data=Response from server port: 8082, msg=success)
-
Spring Cloud Zuul
zuul-server
-
新建項(xiàng)目 [可以從Eureka-client復(fù)制,然后修改spring.application.name和pom文件的artifactId]。
-
引入Eureka-client依賴(lài)和zuul依賴(lài)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
-
啟動(dòng)類(lèi)加注解:
@EnableZuulProxy
-
application.yml 配置文件,加上zuul配置
server: port: 8888 spring: application: name: zuul-server eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ # 將 /demo-hello/ 開(kāi)頭的請(qǐng)求,轉(zhuǎn)到demo-hello組件中 zuul: routes: demo-hello: path: /demo-hello/** serviceId: demo-hello # 也可以直接設(shè)置url # url: http://localhost:8082/
-
啟動(dòng) demo-hello 組件,調(diào)用請(qǐng)求: http://localhost:8888/demo-hello/hello/testGet?param=this_is_param,demo-hello[8082] 得到結(jié)果。等同于直接調(diào)用demo-hello的請(qǐng)求:http://localhost:8082/hello/testGet?param=this_is_param
-
路由前綴
zuul: routes: demo-hello: path: /demo-hello/** serviceId: demo-hello prefix: /pre
我們可以配置zuul.prefix來(lái)設(shè)置統(tǒng)一前綴。像我這樣配置的話(huà),就是得訪(fǎng)問(wèn):http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param,才能跟上面的請(qǐng)求等效。
-
屏蔽服務(wù)、路徑
zuul: ignored-services: demo-hello ignored-patterns: /**/hello/**
請(qǐng)求過(guò)濾
-
我們可以根據(jù)過(guò)濾規(guī)則,對(duì)訪(fǎng)問(wèn)的請(qǐng)求進(jìn)行校驗(yàn)。不符合規(guī)則的可以直接過(guò)濾返回。比如我們可以校驗(yàn)請(qǐng)求的參數(shù)是否有token參數(shù)。
-
新建過(guò)濾器:
@Slf4j public class AccessFilter extends ZuulFilter { /** * 過(guò)濾器類(lèi)型 * pre: 在請(qǐng)求被路由前調(diào)用 * routing: 在路由請(qǐng)求時(shí)調(diào)用 * error: 在處理請(qǐng)求時(shí)發(fā)生錯(cuò)誤時(shí)調(diào)用 * post: 在routing和error過(guò)濾器之后調(diào)用 */ @Override public String filterType() { return "pre"; } /** * 過(guò)濾器的執(zhí)行順序,數(shù)值越小越優(yōu)先 */ @Override public int filterOrder() { return 0; } /** * 是否啟用過(guò)濾 */ @Override public boolean shouldFilter() { return true; } /** * 具體過(guò)濾邏輯 */ @Override public Object run() throws ZuulException { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); log.info("zuul接收到請(qǐng)求,參數(shù):{}", request.getParameterMap()); log.info("zuul接收到請(qǐng)求,參數(shù):{}", request.getParameter("token")); if (request.getParameterMap().get("token") == null) { log.info("請(qǐng)求參數(shù)未包含token字段,返回"); currentContext.setResponseStatusCode(401); currentContext.setSendZuulResponse(false); return null; } log.info("正常請(qǐng)求,放行"); return null; } }
-
創(chuàng)建bean
@Slf4j @Configuration public class ZuulConfig { @Bean public AccessFilter accessFilter() { return new AccessFilter(); } }
-
測(cè)試
請(qǐng)求
http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param&token=gyt%26kal13
可以正常調(diào)到demo-hello組件里的方法。請(qǐng)求
http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param
返回401錯(cuò)誤碼
Spring Cloud Config
config-server
-
引入依賴(lài)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
-
啟動(dòng)類(lèi)添加注解
@EnableConfigServer
-
bootstrap.yaml配置
server: port: 8086 spring: application: name: config-server cloud: config: server: git: uri: https://gitee.com/Aes_yt/spring-cloud-demo.git # git 倉(cāng)庫(kù)的相對(duì)搜索路徑 search-paths: config-repo username: xxxx password: xxxx default-label: master
-
git 配置
第三點(diǎn)使用的是git配置,所以我們需要有一個(gè)git倉(cāng)庫(kù)。我已經(jīng)事先建好了,配置文件放在git倉(cāng)庫(kù)的config-repo路徑下。
在config-repo上傳配置文件,例如上傳不同環(huán)境的三個(gè)配置文件:
config-client.yaml
config: name: myConfig
config-client-dev.yaml
config: name: myConfig-dev
config-client-test.yaml
config: name: myConfig-test
config-client 是我待會(huì)要?jiǎng)?chuàng)建的client項(xiàng)目的application.name,文件名的明明規(guī)則就是 {name}-{profile}.yaml 或 .properties。文件內(nèi)容的配置文件就跟普通的yaml項(xiàng)目一樣,配置所需要的一些配置,我這邊是隨便配置了一個(gè)變量名 ${config.name},后面再輸出打印測(cè)試。
-
先測(cè)試。啟動(dòng)config-server,訪(fǎng)問(wèn)地址 : http://localhost:8086/config-client/dev,可以看到輸出配置信息。
{ "name": "config-client", "profiles": ["dev"], "label": null, "version": "2ec77d4a4f8050fa5a032cf5ff27ff8583d3f663", "state": null, "propertySources": [{ "name": "https://gitee.com/Aes_yt/spring-cloud-demo.git/config-repo/config-client-dev.yaml", "source": { "config.name": "myConfig-dev" } }, { "name": "https://gitee.com/Aes_yt/spring-cloud-demo.git/config-repo/config-client.yaml", "source": { "config.name": "myConfig" } }] }
也可以直接訪(fǎng)問(wèn) http://localhost:8086/config-client-dev.yaml 查看yaml配置內(nèi)容
config: name: myConfig-dev
config-client
-
引入maven依賴(lài)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
-
bootstrap.yaml配置(我這里用application.yaml 配置啟動(dòng)會(huì)報(bào)錯(cuò))
spring: application: name: config-client cloud: config: label: master # config-server的地址 uri: http://localhost:8086/ # 環(huán)境 profile: dev server: port: 8087
-
新建一個(gè)測(cè)試類(lèi),檢測(cè)配置值
@RestController @RequestMapping("/config") public class ConfigTestController { @Value("${config.name}") private String configName; @GetMapping("/test") public String test() { return configName; } }
-
啟動(dòng)項(xiàng)目,能看到控制臺(tái)輸出,會(huì)打印出當(dāng)前使用的配置信息
2023-07-22 10:42:16.447 INFO 13592 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8086/ 2023-07-22 10:42:17.480 INFO 13592 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=config-client, profiles=[dev], label=master, version=2ec77d4a4f8050fa5a032cf5ff27ff8583d3f663, state=null
能看出當(dāng)前環(huán)境是 name=config-client, profiles=[dev], label=master ,所以會(huì)去maven倉(cāng)庫(kù)找到master分支的 config-client-dev 的配置文件。如果找不到的話(huà),在 @Value("${config.name}") 時(shí)則會(huì)報(bào)錯(cuò)。
-
測(cè)試,訪(fǎng)問(wèn) http://localhost:8087/config/test
myConfig-dev
結(jié)合Eureka
-
結(jié)合Eureka使用,首先server和client都要引入Eureka-client依賴(lài),pom中引入
spring-cloud-starter-netflix-eureka-client
。其次,啟動(dòng)類(lèi)都要加上@EnableDiscoveryClient
注解。最后yaml中都需要加上配置eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
,這三個(gè)都可參考上文的Eureka-client配置。 -
config-client加上discovery配置:
spring: application: name: config-client cloud: config: label: master # config-server的地址 # uri: http://localhost:8086/ # 環(huán)境 profile: dev # 使用eureka發(fā)現(xiàn)服務(wù) discovery: enabled: true service-id: config-server eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ server: port: 8087
Spring Cloud Sleuth
Sleuth 能夠?qū)Ψ?wù)間調(diào)用的鏈路進(jìn)行監(jiān)控追蹤,之前學(xué)習(xí) Feign 的時(shí)候,我們用 Feign-client 組件,調(diào)用了 demo-hello 組件的testGet方法,所以我們可以在之前的Feign-client 和 demo-hello 組件的基礎(chǔ)上進(jìn)行修改驗(yàn)證,添加Sleuth依賴(lài),來(lái)觀(guān)察服務(wù)間的調(diào)用情況。
-
添加Sleuth依賴(lài)
-
運(yùn)行,調(diào)用,觀(guān)察打印的日志
feign-client:
2023-07-23 10:10:11.296 DEBUG [feign-client,f307a05d85938646,f8b404471ba7448a,true] 15956 --- [ix-demo-hello-5] 2023-07-23 10:10:11.296 DEBUG [feign-client,f307a05d85938646,f8b404471ba7448a,true] 15956 --- [ix-demo-hello-5] 2023-07-23 10:10:11.416 DEBUG [feign-client,f307a05d85938646,f8b404471ba7448a,true] 15956 --- [ix-demo-hello-5] ...
demo-hello:
2023-07-23 10:10:11.398 INFO [demo-hello,f307a05d85938646,51bf5d6b238302e9,true] 11736 --- [nio-8082-exec-1] com.yt.demo.controller.HelloController : [demo-hello] testGet:Get method: hello
可以從控制臺(tái)的日志發(fā)現(xiàn),日志多了[feign-client,f307a05d85938646,f8b404471ba7448a,true]部分,第一個(gè)參數(shù)代表application.name,第二個(gè)參數(shù) f307a05d85938646 則是一個(gè)請(qǐng)求鏈路的 Trace ID,第三個(gè)參數(shù)f8b404471ba7448a表示SpanId,是一個(gè)基本的工作單元,第四個(gè)參數(shù)表示是否要將該信息輸出到Zipkin等服務(wù)中來(lái)收集和展示。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-613271.html
從feign-client 到 demo-hello 中, Trace ID 都是f307a05d85938646,所以可以將一個(gè)請(qǐng)求在不同服務(wù)中的日志串聯(lián)起來(lái)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-613271.html
到了這里,關(guān)于Spring Cloud Demo的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!