Spring Cloud Demo
本文介绍Spring Cloud 常用的组件的demo代码。gitee代码:gitee.com/Aes_yt/spri...
包括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引入:
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
-
代码:
SpringBootApplication 启动类加入
@EnableEurekaServer
注解。 -
配置:
yamlserver: 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引入:
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
-
代码:
SpringBootApplication 启动类加入
@EnableDiscoveryClient
注解。 -
配置:
yamlserver: port: 8081 spring: application: name: demo-client1 eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
TIPS. 非java语言也可使用Eureka提供的REST API接口接入Server。 wiki
常见问题
-
为什么服务上线了,Eureka Client 不能及时获取到。
Eureka Server 的 REST API 有response cache,需要等缓存过期后才能更新数据。
-
为什么服务下线了,Eureka Server 接口返回的信息还会存在。
应用实例异常挂掉,没有在挂掉之前告知Server 要下线。这个就需要依赖Eureka Server的EvictionTask 去剔除。
-
其他:
springcloud对springboot的版本是有要求的,如果不一致,会启动不起来的。详细可以看官网的版本要求。
Spring Cloud Feign + Spring Cloud Hystrix
demo-hello
-
首先先创建一个 demo 的 module,接入Eureka配置(eureka-client )。设置端口8082,里面只有一个get方法,我们用postman调用 http://localhost:8082/hello/testGet?param=hello,能够正常返回。
java@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:
yamlserver: port: 8082 spring: application: name: demo-hello eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
feign-client
-
创建一个新module。引入Eureka-client依赖,feign依赖和hystrix依赖。
xml<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 之后无此依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
注意:hystrix 在 spring-cloud 2020.0.x 版本废弃,之后的版本推荐使用 Resilience4j 进行服务的熔断。
-
yaml 配置
yamlserver: port: 8083 spring: application: name: feign-client eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ feign: # hystrix熔断开关 hystrix: enabled: true # feign-client的超时时间 client: config: default: connect-timeout: 3000 read-timeout: 3000 logger-level: basic # 设置hystrix服务降级超时时间 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 15000
-
Application 注解
@EnableFeignClients:@EnableFeignClients 是一个 Spring Cloud 注解,用于启用 Feign 客户端的功能。
@EnableCircuitBreaker:
@EnableCircuitBreaker
是 Spring Cloud 提供的一个注解,用于启用熔断器(Circuit Breaker)的功能。java@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients @EnableCircuitBreaker public class FeignClientApplication { public static void main(String[] args) { SpringApplication.run(FeignClientApplication.class, args); } }
-
建立Feign调用Service
java@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 项目的
spring.application.name
,contentxId 就相当于这个调用service的唯一id,path就是统一前缀。fallbackFactory 就是降级后的工厂。所以我们要实现这个工厂。我这边的逻辑,就是记录一下日志,然后返回统一的错误对象。
java@Slf4j @Component public class FeignHelloServiceHystrix implements FallbackFactory<FeignHelloService> { @Override public FeignHelloService create(Throwable cause) { log.error("feign调用helloController报错", cause); return new FeignHelloService() { public BaseResp<String> testGet(String param) { return BaseResp.error(param); } }; } }
-
测试一下,
java@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秒钟才响应或者直接抛出异常,都是会进入FeignHelloServiceHystrix中打印日志。
附加
-
Feign 加日志打印
-
xml配置Feign客户端
yaml# Feign 日志配置 logging: level: com.yt.demo.service.feign: debug
-
Feign 配置
java/** * Feign 配置 */ @Slf4j @Configuration public class FeignConfig { /** * NONE:不记录任何信息 * BASIC:仅记录请求方法、URL以及响应状态码和执行时间. * HEADERS:除了记录BASIC级别的信息外,还会记录请求和响应的头信息 * FULL:记录所有请求与响应的明细,包括头信息、请求体、元数据 */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
-
效果如下:
yaml2023-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 里面新增文件上传方法
java@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 注解,参数加上:
produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE
-
常见问题
-
demo项目的方法返回报错,或者超时,都并没有进入熔断工厂。
检查一下feign-client的hystrix是否启用:
feign.hystrix.enabled: true
-
配置了feign-client的超时时间为3s,demo返回时间6s,但是1s就马上进入熔断工厂报超时,并没有等待3s。
feign-client的超时时间和hystrix的超时时间都要配置。
-
配置了超时时间,但是还是不生效。
根据你的cloud版本搜索一下,对应的配置怎么配。有可能不同版本的配置方法不一样,单词改变了之类的都是有可能的。
-
feign调用报错:Load balancer does not have available server for client : xxx
feign客户端的yaml配置加上
fetch-registry: true
yamleureka: client: service-url: defaultZone: http://localhost:8761/eureka/ fetch-registry: true
Spring Cloud Ribbon
demo-hello
-
demo-hello 复用上面Feign的controller新增一个测试方法,打印出当前服务器端口
java@GetMapping("/testRibbon") public BaseResp<String> testRibbon(@RequestParam("param") String param, HttpServletRequest httpServletRequest) { log.info("接收到请求,参数:{}, serverPort:{}", param, httpServletRequest.getServerPort()); return BaseResp.success("Response from server port: " + httpServletRequest.getServerPort()); }
-
启动项目,之后修改application.xml的端口号port,重新启动一个实例。
-
启动成功之后,在Eureka界面可以看到两个启动的实例。
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
-
新建一个项目。[可以从Eureka-client复制,然后修改spring.application.name和pom文件的artifactId]。
-
引入ribbon依赖
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
-
新建ribbon配置类,重点是用@LoadBalance注解来声明restTemplate具有负载均衡能力。而且这样在使用restTeamplate的时候就能通过eureka上面的服务名来调用服务了,
java@Slf4j @Configuration public class RibbonConfig { @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
-
新建一个测试类,直接调用十次请求
java@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); } }
-
返回结果:
yaml2023-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的默认负载均衡策略是ZoneAvoidanceRule,可以看出请求分别调到了8084和8082两个服务实例上。
-
负载均衡策略配置
-
Ribbon内置的负载均衡规则:
规则名称 特点 AvailabilityFilteringRule 过滤掉一直连接失败的被标记为circuit tripped的后端Server,并 过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate 来包含过滤server的逻辑,其实就是检查status里记录的各个server 的运行状态 BestAvailableRule 选择一个最小的并发请求的server,逐个考察server, 如果Server被tripped了,则跳过 RandomRule 随机选择一个Server WeightedResponseTimeRule 根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低 RetryRule 对选定的负载均衡策略加上重试机制,在一个配置时间段内当 选择Server不成功,则一直尝试使用subRule的方式选择一个 可用的Server RoundRobinRule 轮询选择,轮询index,选择index对应位置的Server ZoneAvoidanceRule 复合判断Server所在区域的性能和Server的可用性 选择Server,在没有区域的环境下,类似于轮询(RandomRule) -
修改策略为随机:
RibbonConfig.java 新增配置[全局]
java/** * 配置轮询策略为RandomRule * 其他的策略配置也一样,策略类路径都是 com.netflix.loadbalancer.xxx */ @Bean public IRule ribbonRule(){ return new RandomRule(); }
或:按服务粒度进行配置:(demo-hello 是目标服务的服务名)
yamldemo-hello: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
我直接配置全局的
ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
不生效,不知道是不是不支持全局配置。效果:
java2023-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
-
新建项目 [可以从Eureka-client复制,然后修改spring.application.name和pom文件的artifactId]。
-
引入Eureka-client依赖和zuul依赖
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
-
启动类加注解:
@EnableZuulProxy
-
application.yml 配置文件,加上zuul配置
yamlserver: port: 8888 spring: application: name: zuul-server eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ # 将 /demo-hello/ 开头的请求,转到demo-hello组件中 zuul: routes: demo-hello: path: /demo-hello/** serviceId: demo-hello # 也可以直接设置url # url: http://localhost:8082/
-
启动 demo-hello 组件,调用请求: http://localhost:8888/demo-hello/hello/testGet?param=this_is_param,demo-hello[8082] 得到结果。等同于直接调用demo-hello的请求:http://localhost:8082/hello/testGet?param=this_is_param
-
路由前缀
yamlzuul: routes: demo-hello: path: /demo-hello/** serviceId: demo-hello prefix: /pre
我们可以配置zuul.prefix来设置统一前缀。像我这样配置的话,就是得访问:http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param,才能跟上面的请求等效。
-
屏蔽服务、路径
yamlzuul: ignored-services: demo-hello ignored-patterns: /**/hello/**
请求过滤
-
我们可以根据过滤规则,对访问的请求进行校验。不符合规则的可以直接过滤返回。比如我们可以校验请求的参数是否有token参数。
-
新建过滤器:
java@Slf4j public class AccessFilter extends ZuulFilter { /** * 过滤器类型 * pre: 在请求被路由前调用 * routing: 在路由请求时调用 * error: 在处理请求时发生错误时调用 * post: 在routing和error过滤器之后调用 */ @Override public String filterType() { return "pre"; } /** * 过滤器的执行顺序,数值越小越优先 */ @Override public int filterOrder() { return 0; } /** * 是否启用过滤 */ @Override public boolean shouldFilter() { return true; } /** * 具体过滤逻辑 */ @Override public Object run() throws ZuulException { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); log.info("zuul接收到请求,参数:{}", request.getParameterMap()); log.info("zuul接收到请求,参数:{}", request.getParameter("token")); if (request.getParameterMap().get("token") == null) { log.info("请求参数未包含token字段,返回"); currentContext.setResponseStatusCode(401); currentContext.setSendZuulResponse(false); return null; } log.info("正常请求,放行"); return null; } }
-
创建bean
java@Slf4j @Configuration public class ZuulConfig { @Bean public AccessFilter accessFilter() { return new AccessFilter(); } }
-
测试
请求
http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param&token=gyt%26kal13
可以正常调到demo-hello组件里的方法。请求
http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param
返回401错误码
Spring Cloud Config
config-server
-
引入依赖
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
-
启动类添加注解
@EnableConfigServer
-
bootstrap.yaml配置
yamlserver: port: 8086 spring: application: name: config-server cloud: config: server: git: uri: https://gitee.com/Aes_yt/spring-cloud-demo.git # git 仓库的相对搜索路径 search-paths: config-repo username: xxxx password: xxxx default-label: master
-
git 配置
第三点使用的是git配置,所以我们需要有一个git仓库。我已经事先建好了,配置文件放在git仓库的config-repo路径下。
在config-repo上传配置文件,例如上传不同环境的三个配置文件:
config-client.yaml
yamlconfig: name: myConfig
config-client-dev.yaml
yamlconfig: name: myConfig-dev
config-client-test.yaml
yamlconfig: name: myConfig-test
config-client 是我待会要创建的client项目的application.name,文件名的明明规则就是 {name}-{profile}.yaml 或 .properties。文件内容的配置文件就跟普通的yaml项目一样,配置所需要的一些配置,我这边是随便配置了一个变量名 ${config.name},后面再输出打印测试。
-
先测试。启动config-server,访问地址 : http://localhost:8086/config-client/dev,可以看到输出配置信息。
json{ "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" } }] }
也可以直接访问 http://localhost:8086/config-client-dev.yaml 查看yaml配置内容
yamlconfig: name: myConfig-dev
config-client
-
引入maven依赖
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
-
bootstrap.yaml配置(我这里用application.yaml 配置启动会报错)
yamlspring: application: name: config-client cloud: config: label: master # config-server的地址 uri: http://localhost:8086/ # 环境 profile: dev server: port: 8087
-
新建一个测试类,检测配置值
java@RestController @RequestMapping("/config") public class ConfigTestController { @Value("${config.name}") private String configName; @GetMapping("/test") public String test() { return configName; } }
-
启动项目,能看到控制台输出,会打印出当前使用的配置信息
less2023-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
能看出当前环境是 name=config-client, profiles=[dev], label=master ,所以会去maven仓库找到master分支的 config-client-dev 的配置文件。如果找不到的话,在 @Value("${config.name}") 时则会报错。
-
测试,访问 http://localhost:8087/config/test
myConfig-dev
结合Eureka
-
结合Eureka使用,首先server和client都要引入Eureka-client依赖,pom中引入
spring-cloud-starter-netflix-eureka-client
。其次,启动类都要加上@EnableDiscoveryClient
注解。最后yaml中都需要加上配置eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
,这三个都可参考上文的Eureka-client配置。 -
config-client加上discovery配置:
yamlspring: application: name: config-client cloud: config: label: master # config-server的地址 # uri: http://localhost:8086/ # 环境 profile: dev # 使用eureka发现服务 discovery: enabled: true service-id: config-server eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ server: port: 8087
Spring Cloud Sleuth
Sleuth 能够对服务间调用的链路进行监控追踪,之前学习 Feign 的时候,我们用 Feign-client 组件,调用了 demo-hello 组件的testGet方法,所以我们可以在之前的Feign-client 和 demo-hello 组件的基础上进行修改验证,添加Sleuth依赖,来观察服务间的调用情况。
-
添加Sleuth依赖
-
运行,调用,观察打印的日志
feign-client:
xml2023-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:
yaml2023-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
可以从控制台的日志发现,日志多了[feign-client,f307a05d85938646,f8b404471ba7448a,true]部分,第一个参数代表application.name,第二个参数 f307a05d85938646 则是一个请求链路的 Trace ID,第三个参数f8b404471ba7448a表示SpanId,是一个基本的工作单元,第四个参数表示是否要将该信息输出到Zipkin等服务中来收集和展示。
从feign-client 到 demo-hello 中, Trace ID 都是f307a05d85938646,所以可以将一个请求在不同服务中的日志串联起来。