Spring Cloud(Dalston.SR5)--Hystrix 断路器-缓存
在 Spring Cloud 中可以使用注解的方式来支持 Hystrix 的缓存,缓存与合并请求功能需要先初始化请求上下文才能实现,因此,必须实现 javax.servlet.Filter 用于创建和销毁 Hystrix 的请求上下文,而缓存的注解有 @CacheResult、@CacheRemove,@CacheResult 注解必须和 @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(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
HystrixRequestContext.setContextOnCurrentThread(context);
try{
chain.doFilter(request,response);
}catch(Exceptionex){
ex.printStackTrace();
}
}
@Override
publicvoiddestroy(){
if(context!=null){
context.shutdown();
}
}
}
- 创建服务调用
注解 @CacheResult 必须和 @HystrixCommand 同时使用,@CacheResult 注解的 cacheKeyMethod 参数指定的方法必须和 @CacheResult 标注的方法参数一致,并且相同参数产生的 key 值应该一致;
如果数据存在修改,则必须使用 @CacheRemove 注解标注修改方法,同样也需要指定 cacheKeyMethod 参数,表示需要移除缓存的 key,其 commandKey 参数也必须指定和 @HystrixCommand 注解的 commandKey 值一致;
如果不指定 @CacheResult 和 @CacheRemove 注解的 cacheKeyMethod 参数,也可使用 @CacheKey 注解来标注方法的参数,表示使用方法的参数来作为缓存 key
package org.lixue;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
public class HelloWorldClient{
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod="speakFallback",commandKey="hello-world",
threadPoolKey="hello-world",groupKey="hello-world",
commandProperties={
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="500")
},
threadPoolProperties={
@HystrixProperty(name="coreSize",value="50")
}
)
@CacheResult(cacheKeyMethod="speakCacheKey")
public String speak(String name){
if(name==null||"".equals(name)){
name="null";
}
return restTemplate.getForObject("http://HELLOWORLD-PROVIDER/speaks?names="+name,String.class);
}
/**
*生成speak方法的缓存Key
*
*@param name
*@return
*/
private String speakCacheKey(String name){
return"speak."+name;
}
/**
*修改speak数据,移除缓存
*
*@param name
*@return
*/
@CacheRemove(commandKey="hello-world",cacheKeyMethod="speakCacheKey")
public String updateSpeak(String name){
return name;
}
/**
*speak返回的回退方法
*
*@param name
*@return
*/
private String speakFallback(String name){
return"call error,name is"+name;
}
}
- 服务增加日志
@RequestMapping(method=RequestMethod.GET,name="speak",path="/speaks",
produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
public Map<String,String> speaks(@RequestParam(value="names")String names) throws InterruptedException{
System.out.println("speaksnames="+names);
Map<String,String>map=newHashMap<>();
if(names==null||"".equals(names)){
return map;
}
String[] splitName=names.split(",");
for(Stringname:splitName){
map.put(name,"HelloWorld"+name+"Port="+port);
}
return map;
}
- 测试验证
由于我们使用了 Ribbon 因此首先启动 eureka-server 和 service-provider 服务,然后启动该项目,访问 http://localhost:8077/speak?name=abc 可以看到能正常返回信息,如下:
{"abc":"Hello World abc Port=8002"}
服务输出日志:
speaks names=abc
多次刷新,可以看到服务的日志只显示了一次,表示后续的刷新访问都是使用的 Hystrix 缓存。