在 Spring Cloud 中可以使用注解的方式来支持 Hystrix 的合并请求,缓存与合并请求功能需要先初始化请求上下文才能实现,因此,必须实现 javax.servlet.Filter 用于创建和销毁 Hystrix 的请求上下文,合并请求的注解需要用到 @HystrixCollapser 和 @HystrixCommand ,示例如下:
创建 Filter
和缓存一样,在 Filter 初始化时就创建 HystrixRequestContext,然后在每个请求调用 doFilter 方法时,将初始化的上下文赋值到当前线程存储,这样就能在全局使用 Hystrix 的缓存和合并请求
package org.lixue;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
importj ava.io.IOException;
@WebFilter(urlPatterns="/*",filterName="HystrixRequestContextFilter")
public class HystrixRequestContextFilter implements Filter{
HystrixRequestContext context=null;
@Override
public void init(FilterConfig filterConfig) throws ServletException{
context=HystrixRequestContext.initializeContext();
}
@Override
publicvoid doFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain) throws IOException,ServletException{
HystrixRequestContext.setContextOnCurrentThread(context);
try{
chain.doFilter(request,response);
}catch(Exceptionex){
ex.printStackTrace();
}
}
@Override
publicvoiddestroy(){
if(context!=null){
context.shutdown();
}
}
}
创建服务调用
注解 @HystrixCollapser 标注合并请求的方法,需要设置该注解的 batchMethod 属性,该属性设置用于处理批量请求的方法,可以设置 collapserProperties 属性,表示合并请求相关参数配置,这里配置了 timerDelayInMilliseconds 属性,表示合并 5 秒的请求;使用 @HystrixCommand 标注了实际批量请求的方法。
package org.lixue;
import com.alibaba.fastjson.JSON;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
@Component
public class HelloWorldCollapseClient{
@Autowired
private RestTemplate restTemplate;
@HystrixCollapser(batchMethod="speakCollapse",collapserProperties={
@HystrixProperty(name="timerDelayInMilliseconds",value="5000")
})
public Future
speak(String name){ return null;
}
@HystrixCommand
private List
speakCollapse(List names){ System.out.println("speakNamesiscall,namesis"+names);
String jsonResponse=
restTemplate.getForObject("http://HELLOWORLD-PROVIDER/speaks?names="**\+ StringUtils.join(names,**',') ,String.class);
Map<String,String> mapResponse=(Map<String,String>)JSON.parse(jsonResponse);
List
list=new LinkedList<>(); for(int i=0;i<names.size();i++){
list.add(mapResponse.get(names.get(i)));
}
return list;
}
}
测试验证
由于我们使用了 Ribbon 因此首先启动 eureka-server 和 service-provider 服务,然后启动该项目,访问 http://localhost:8077/speak?name=abc 可以看到能正常返回信息,如下:
Hello World abc Port=8080
服务输出日志:
speaks names=abc
使用多个浏览器选项页面,访问 http://localhost:8077/speak?name=abc 多次,可以看到服务都是等待了 5秒后返回,并且都是同时返回,而服务端只被请求了一次。