如下为博主写Hystrix系列的文章列表html
点击查看 Hystrix入门java
点击查看 Hystrix命令执行git
点击查看 Hystrix处理异常机制(降级方法)github
点击查看 Hystrix命令名称、分组、线程池web
您能够经过在 HystrixCommand
或 HystrixObservableCommand
上实现 getCacheKey()
方法来启用请求缓存,以下所示:缓存
public class CommandHelloRequestCache extends HystrixCommand<Boolean> { private final int value; protected CommandHelloRequestCache(int value) { super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); this.value = value; } @Override protected Boolean run() { return value == 0 || value % 2 == 0; } @Override protected String getCacheKey() { return String.valueOf(value); } }
点击查看 完整源码(含单元测试)app
因为依赖请求上下文,因此必须初始化 HystrixRequestContext
。ide
在一个简单单元测试中使用,以下:函数
@Test public void testWithoutCacheHits() { HystrixRequestContext context = HystrixRequestContext.initializeContext(); try { assertTrue(new CommandHelloRequestCache(2).execute()); assertFalse(new CommandHelloRequestCache(1).execute()); assertTrue(new CommandHelloRequestCache(0).execute()); assertTrue(new CommandHelloRequestCache(58672).execute()); } finally { context.shutdown(); } }
一般,请求上下文将被初始化,并经过封装用户请求或其余生命周期钩子的ServletFilter关闭。单元测试
下面示例,展现了在请求上下文中,命令如何从缓存检索它们的值(以及如何查询一个对象肯定它的值是否来自缓存 ):
@Test public void testWithCacheHits() { HystrixRequestContext context = HystrixRequestContext.initializeContext(); try { CommandHelloRequestCache command2a = new CommandHelloRequestCache(2); CommandHelloRequestCache command2b = new CommandHelloRequestCache(2); assertTrue(command2a.execute()); // 第一次执行这个命令时不是从缓存返回的值 assertFalse(command2a.isResponseFromCache()); assertTrue(command2b.execute()); // 第二次执行这个命令时是从缓存返回的值 assertTrue(command2b.isResponseFromCache()); } finally { context.shutdown(); } // 开启一个新的请求上下文 context = HystrixRequestContext.initializeContext(); try { CommandHelloRequestCache command3b = new CommandHelloRequestCache(2); assertTrue(command3b.execute()); // 这个新请求执行这个命令也不会从缓存返回值 assertFalse(command3b.isResponseFromCache()); } finally { context.shutdown(); } }
请求合并者使多个请求在单个HystrixCommand实例被批量执行。自批处理建立后,合并者可使用批次大小和运行时间做为执行批次处理的触发器。
Hystrix 支持的请求合并有两种:请求范围和全局范围。这个能够在合并器构造函数中配置,默认状况下是请求范围。
请求范围的合并器收集每一个 HystrixRequestContext
的批处理,而全局范围的合并器则会在多个 HystrixRequestContext
中收集一批批处理。 所以,若是下游依赖项不能在单个命令调用中处理多个 HystrixRequestContext
,那么请求做用域合并者作出了恰当的选择。
在Netflix(Hystrix开源者),只使用请求做用域的合并器,由于全部当前的系统都是创建在每一个命令使用单个HystrixRequestContext的假设之上。 因为一批次仅为每一个请求,在同一请求命令使用不一样参数并行执行时,合并是有效的。
下面是一个简单的例子,说明如何实现一个请求范围的 HystrixCollapser
:
public class CommandHelloCollapser extends HystrixCollapser<List<String>, String, Integer> { private final Integer key; public CommandHelloCollapser(Integer key) { this.key = key; } @Override public Integer getRequestArgument() { return key; } @Override protected HystrixCommand<List<String>> createCommand(final Collection<CollapsedRequest<String, Integer>> requests) { return new BatchCommand(requests); } @Override protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, Integer>> requests) { int count = 0; for (CollapsedRequest<String, Integer> request : requests) { request.setResponse(batchResponse.get(count++)); } } private static final class BatchCommand extends HystrixCommand<List<String>> { private final Collection<CollapsedRequest<String, Integer>> requests; private BatchCommand(Collection<CollapsedRequest<String, Integer>> requests) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")) .andCommandKey(HystrixCommandKey.Factory.asKey("GetValueForKey"))); this.requests = requests; } @Override protected List<String> run() { ArrayList<String> response = new ArrayList<String>(); for (CollapsedRequest<String, Integer> request : requests) { // artificial response for each argument received in the batch response.add("ValueForKey: " + request.getArgument()); } return response; } } }
点击查看 完整源码以及单元测试
下面的单元测试展现了如何使用一个合并器自动将 CommandHelloCollapser
的4个执行在一个 HystrixCommand
中执行:
@Test public void testCollapser() throws Exception { HystrixRequestContext context = HystrixRequestContext.initializeContext(); try { Future<String> f1 = new CommandHelloCollapser(1).queue(); Future<String> f2 = new CommandHelloCollapser(2).queue(); Future<String> f3 = new CommandHelloCollapser(3).queue(); Future<String> f4 = new CommandHelloCollapser(4).queue(); assertEquals("ValueForKey: 1", f1.get()); assertEquals("ValueForKey: 2", f2.get()); assertEquals("ValueForKey: 3", f3.get()); assertEquals("ValueForKey: 4", f4.get()); int numExecuted = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size(); System.err.println("num executed: " + numExecuted); // 断言此批次命令"Command Name:Hello Collapser"实际被执行了而却仅仅执行了它 // 一次或两次(因为这个例子使用了真实的定时器,源于调度程序的不肯定性) if (numExecuted > 2) { fail("some of the commands should have been collapsed"); } System.err.println("HystrixRequestLog.getCurrentRequest().getAllExecutedCommands(): " + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands()); int numLogs = 0; for (HystrixInvokableInfo<?> command : HystrixRequestLog.getCurrentRequest().getAllExecutedCommands()) { numLogs++; // 这个命令执行是咱们所指望的 assertEquals("Command Name:Hello Collapser", command.getCommandKey().name()); System.err.println(command.getCommandKey().name() + " => command.getExecutionEvents(): " + command.getExecutionEvents()); // 确认是一个合并器的命令执行 assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED)); assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS)); } assertEquals(numExecuted, numLogs); } finally { context.shutdown(); } }
为了使用请求范围特性( 请求缓存,请求合并,请求日志 )必须管理 HystrixRequestContext
生命周期(或者实现一个可替代的 HystrixConcurrencyStrategy
)
这意味着在一个请求前必须执行以下语句:
HystrixRequestContext context = HystrixRequestContext.initializeContext();
在请求执行后执行如下语句:
context.shutdown();
在一个标准的java web应用中,可使用 Servlet Filter (过滤器)初始化 HystrixRequestContext
生命周期,实现过滤器实现方式以下:
public class HystrixRequestContextServletFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HystrixRequestContext context = HystrixRequestContext.initializeContext(); try { chain.doFilter(request, response); } finally { context.shutdown(); } } }
而后经过在web.xml中添加一段配置来启用全部进来的请求过滤器 ,示例以下:
<filter> <display-name>HystrixRequestContextServletFilter</display-name> <filter-name>HystrixRequestContextServletFilter</filter-name> <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter</filter-class> </filter> <filter-mapping> <filter-name>HystrixRequestContextServletFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
转帖请注明原贴地址:https://my.oschina.net/u/2342969/blog/1817093