diff --git a/dev-protocol-springcloud/SpringCloud项目介绍.md b/dev-protocol-springcloud/SpringCloud项目介绍.md index a48e422..d1075b3 100644 --- a/dev-protocol-springcloud/SpringCloud项目介绍.md +++ b/dev-protocol-springcloud/SpringCloud项目介绍.md @@ -10,7 +10,7 @@ - 分布式链路、日志追踪 - (Sleuth + Zipkin) - [dev-protocol-springcloud-sleuth-zipkin](dev-protocol-springcloud-sleuth-zipkin) - 微服务容错 - (SpringCloud Netflix Hystrix) - - todo + - [dev-protocol-springcloud-hystrix](dev-protocol-springcloud-hystrix) - 消息驱动微服务 - (SpringCloud Stream) - todo - 分布式事务 - (SpringCloud Alibaba Seata) diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/NetflixHystrix.md b/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/NetflixHystrix.md index ff18d86..3146cbb 100644 --- a/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/NetflixHystrix.md +++ b/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/NetflixHystrix.md @@ -27,7 +27,7 @@ - [NacosClientHystrixCommand.java] - [NacosClientHystrixObservableCommand.java] ### 编程方式开启 Hystrix 请求缓存 - +- 先编写过滤器 [HystrixRequestContextServletFilter.java] ### 注解方式开启 Hystrix 请求缓存 diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/controller/HystrixController.java b/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/controller/HystrixController.java index 9f70d11..d500009 100644 --- a/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/controller/HystrixController.java +++ b/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/controller/HystrixController.java @@ -2,11 +2,11 @@ package org.example.controller; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; +import org.example.hystrix.CacheHystrixCommand; import org.example.hystrix.NacosClientHystrixCommand; import org.example.hystrix.NacosClientHystrixObservableCommand; import org.example.hystrix.UseHystrixCommandAnnotation; import org.example.service.NacosClientService4HystrixDemo; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -129,4 +129,39 @@ public class HystrixController { JSON.toJSONString(result), Thread.currentThread().getName()); return result.get(0); // 取一个返回 } + + @GetMapping("/cache-hystrix-command") + public void cacheHystrixCommand(@RequestParam String serviceId) { + + // 使用缓存 Command, 连续发起两次请求 + CacheHystrixCommand command1 = new CacheHystrixCommand( + nacosClientService4HystrixDemo, serviceId + ); + CacheHystrixCommand command2 = new CacheHystrixCommand( + nacosClientService4HystrixDemo, serviceId + ); + + List result01 = command1.execute(); + List result02 = command2.execute(); + // 看是否只执行了一次 run 方法 + log.info("result01, result02: [{}], [{}]", + JSON.toJSONString(result01), JSON.toJSONString(result02)); + + // 清除缓存 + CacheHystrixCommand.flushRequestCache(serviceId); + + // 使用缓存 Command, 发起两次请求 + CacheHystrixCommand command3 = new CacheHystrixCommand( + nacosClientService4HystrixDemo, serviceId + ); + CacheHystrixCommand command4 = new CacheHystrixCommand( + nacosClientService4HystrixDemo, serviceId + ); + + List result03 = command3.execute(); + List result04 = command4.execute(); + // 看是否成功清除缓存 + log.info("result03, result04: [{}], [{}]", + JSON.toJSONString(result03), JSON.toJSONString(result04)); + } } diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/filter/HystrixRequestContextServletFilter.java b/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/filter/HystrixRequestContextServletFilter.java index e445959..6d7ae69 100644 --- a/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/filter/HystrixRequestContextServletFilter.java +++ b/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/filter/HystrixRequestContextServletFilter.java @@ -49,6 +49,7 @@ public class HystrixRequestContextServletFilter implements Filter { /** *

配置 Hystrix 的并发策略

+ * 重写的原因, 是官方不建议引用 Sleuth, 但是我们重写了下述代码 * */ public void hystrixConcurrencyStrategyConfig() { @@ -59,7 +60,7 @@ public class HystrixRequestContextServletFilter implements Filter { HystrixConcurrencyStrategy strategy = HystrixPlugins.getInstance().getConcurrencyStrategy(); if (strategy instanceof HystrixConcurrencyStrategyDefault) { - // 如果已经就是我们想要配置的 + // 如果已经就是我们想要配置的, 直接返回 return; } @@ -83,6 +84,7 @@ public class HystrixRequestContextServletFilter implements Filter { log.info("config hystrix concurrency strategy success"); } catch (Exception ex) { + // 注册失败的可能性很小, 所以用大 catch log.error("Failed to register Hystrix Concurrency Strategy: [{}]", ex.getMessage(), ex); } diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/hystrix/CacheHystrixCommand.java b/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/hystrix/CacheHystrixCommand.java new file mode 100644 index 0000000..4753ad0 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-hystrix/src/main/java/org/example/hystrix/CacheHystrixCommand.java @@ -0,0 +1,75 @@ +package org.example.hystrix; + +import com.netflix.hystrix.HystrixCommand; +import com.netflix.hystrix.HystrixCommandGroupKey; +import com.netflix.hystrix.HystrixCommandKey; +import com.netflix.hystrix.HystrixRequestCache; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.example.service.NacosClientService4HystrixDemo; +import org.springframework.cloud.client.ServiceInstance; + +import java.util.Collections; + +/** + *

带有缓存功能的 Hystrix

+ * */ +@Slf4j +public class CacheHystrixCommand extends HystrixCommand> { + + /** 需要保护的服务 */ + private final NacosClientService4HystrixDemo nacosClientService; + + /** 方法需要传递的参数 */ + private final String serviceId; + + private static final HystrixCommandKey CACHED_KEY = + HystrixCommandKey.Factory.asKey("CacheHystrixCommand"); + + public CacheHystrixCommand(NacosClientService4HystrixDemo nacosClientService, String serviceId) { + + super( + HystrixCommand.Setter + .withGroupKey(HystrixCommandGroupKey + .Factory.asKey("CacheHystrixCommandGroup")) + .andCommandKey(CACHED_KEY) + ); + + this.nacosClientService = nacosClientService; + this.serviceId = serviceId; + } + + @Override + protected List run() throws Exception { + + log.info("CacheHystrixCommand In Hystrix Command to get service instance:" + + " [{}], [{}]", this.serviceId, Thread.currentThread().getName()); + return this.nacosClientService.getNacosClientInfo(this.serviceId); + } + + @Override + protected String getCacheKey() { + // fixme 可以进行自定义, 只要保证唯一的请求返回唯一的值即可 + return serviceId; + } + + @Override + protected List getFallback() { + // todo 这里可以自己添加一些 warning 日志来进行表示 + return Collections.emptyList(); + } + + /** + *

根据缓存 key 清理在一次 Hystrix 请求上下文中的缓存

+ * */ + public static void flushRequestCache(String serviceId) { + + HystrixRequestCache.getInstance( + CACHED_KEY, + HystrixConcurrencyStrategyDefault.getInstance() + ).clear(serviceId); + log.info("flush request cache in hystrix command: [{}], [{}]", + serviceId, Thread.currentThread().getName()); + } +}