一、hystrix执行
1、同步执行
- 简单的继承HystrixCommand,具体的执行逻辑在run方法中
- 同步执行直接调用command的execute方法
class HelloHystrixCommand extends HystrixCommand<String> {
private String name;
HelloHystrixCommand(String name) {
super(HystrixCommandGroupKey.Factory.asKey("test"));
this.name = name;
}
@Override
protected String run() throws Exception {
TimeUnit.MILLISECONDS.sleep(20);
return "hello " + name;
}
}
// 1、直接执行,同步调用
long start = System.currentTimeMillis();
System.out.println(start);
System.out.println(new HelloHystrixCommand("world").execute());
System.out.println(System.currentTimeMillis() - start);
2、异步执行
- 利用java的future来异步执行
- execute就相当于queue().get()
Future<String> future = new HelloHystrixCommand("bob").queue();
try {
System.out.println(future.get(20, TimeUnit.MILLISECONDS));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
System.out.println("获取超时!");
}
3、Reactive执行
- 上面两个示例都是HystrixCommand来进行执行的
- HystrixCommand是hystrix通过封装run方法获取Observable,然后获取future来达到同步和异步的效果的
- HystrixObserableCommand是自己通过construct方法封装observable,自己创建数据源,然后调用observe和toObservable再获取future,效果和HystrixCommand一样,方便使用Rxjava开发的用户
// 自己封装Observable,不依赖hystrix进行封装
class HelloObservableCommand extends HystrixObservableCommand<String> {
private String value;
public HelloObservableCommand(String value) {
super(HystrixCommandGroupKey.Factory.asKey("observable"));
this.value = value;
}
@Override
protected Observable<String> construct() {
return Observable.just(value);
}
}
// 获取construct创建的Observable对象
HelloObservableCommand observableCommand = new HelloObservableCommand("world");
// observableCommand.observe().subscribe(value -> System.out.println("hello " + value));
observableCommand.toObservable().subscribe(value -> System.out.println("hello " + value));
二、失败转移
可以在HystrixCommand中重写getFallback方法来应对execute和queue方法发生错误的情况
class FailbackHystrixCommand extends HystrixCommand<String> {
private String name;
FailbackHystrixCommand(String name) {
super(HystrixCommandGroupKey.Factory.asKey("test"));
this.name = name;
}
@Override
protected String run() throws Exception {
throw new RuntimeException("run exception");
}
@Override
protected String getFallback() {
return "run execute exception!";
}
}
@Test
public void fallback() {
FailbackHystrixCommand fail = new FailbackHystrixCommand("fail");
System.out.println(fail.execute());
}
三、命令名称&命令组&线程池名称
- 命令组名称必须要指定,它仅仅是一个逻辑概念,它的作用是将多个同类型的命令进行归类,比如将某个业务的command归为同一类
- 通过HystrixCommandGroupKey.Factory.asKey("test")指定命令组
- 命令名称可以不指定,默认是类名,也可以自己指定
- 通过HystrixCommandKey.Factory.asKey("testKey")指定命令名称
- 线程池名称的作用是当某些命令属于同一个group,但是属于不同单元,它就类似于group的细分类别
- 通过HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")设置线程池key名称
class HelloHystrixCommand extends HystrixCommand<String> {
private String name;
HelloHystrixCommand(String name) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("test"))
.andCommandKey(HystrixCommandKey.Factory.asKey("testKey"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("testThreadKey")));
this.name = name;
}
@Override
protected String run() throws Exception {
TimeUnit.MILLISECONDS.sleep(20);
return "hello " + name;
}
}
四、请求缓存
- 所谓请求缓存,可以自定义缓存命中策略,使得后面命中缓存策略的key走缓存逻辑,而不用再去调用run方法来执行
- 我们可以在getCacheKey方法中自定义缓存命中策略
- 只有在同一个context下才会命中缓存,跨context之前缓存不会命中
- 比如说缓存命中逻辑为请求的参数一致,那么后面的相同请求参数就会走缓存
class HystrixCommandWithCache extends HystrixCommand<String> {
private String data;
HystrixCommandWithCache(String data) {
super(HystrixCommandGroupKey.Factory.asKey("cache"));
this.data = data;
}
@Override
protected String run() throws Exception {
return "run " + data;
}
@Override
protected String getCacheKey() {
// 自定义缓存命中策略为相同data参数即为命中策略
return data;
}
}
public void commandWithCache() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
HystrixCommandWithCache man = new HystrixCommandWithCache("man");
HystrixCommandWithCache other = new HystrixCommandWithCache("other");
HystrixCommandWithCache man1 = new HystrixCommandWithCache("man");
System.out.println(man.execute());
// 第一次访问所以返回为false
System.out.println(man.isResponseFromCache());
System.out.println(other.execute());
// data参数不同,返回false
System.out.println(other.isResponseFromCache());
System.out.println(man1.execute());
// man第二次访问,返回为true
System.out.println(man1.isResponseFromCache());
context.shutdown();
HystrixRequestContext context1 = HystrixRequestContext.initializeContext();
HystrixCommandWithCache man2 = new HystrixCommandWithCache("man");
System.out.println(man2.execute());
// 跨context不会命中缓存
System.out.println(man2.isResponseFromCache());
context1.shutdown();
}
五、Request Collapsing
六、HystrixRequestContext
- 如果想使用request级别的特性,那么就必须使用这个HystrixRequestContext
1、创建方式
HystrixRequestContext context = HystrixRequestContext.initializeContext();
2、web应用使用HystrixRequestContext
每一个请求都开启一个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生效
<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>