主要介绍Hystrix各接口和注解的使用方法。
创建请求命令
Hystrix命令就是我们之前所说的HystrixCommand,他用来封装具体的依赖服务调用逻辑。
继承方式实现HystrixCommand
首先通过代码实现HystrixCommand
package cn.sh.ribbon.command;
import cn.sh.common.entity.User;
import com.netflix.hystrix.HystrixCommand;
import org.springframework.web.client.RestTemplate;
/**
* @author sh
*/
public class UserCommand extends HystrixCommand<User> {
private RestTemplate restTemplate;
private Long id;
public UserCommand(Setter setter, RestTemplate restTemplate, Long id) {
super(setter);
this.restTemplate = restTemplate;
this.id = id;
}
@Override
protected User run() throws Exception {
return restTemplate.getForObject("http://USER-SERVICE/users/{1}", User.class, id);
}
}
通过上面实现的UserCommand,我们即可以实现请求的同步执行也可以实现异步执行,相关代码如下:
package cn.sh.ribbon.service;
import cn.sh.common.entity.User;
import cn.sh.ribbon.command.UserCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* @author sh
*/
@Service
public class HelloService {
private static final Logger logger = LoggerFactory.getLogger(HelloService.class);
@Autowired
private RestTemplate restTemplate;
/**
* 第一种使用命令的方式
* @param id
* @return
*/
public User getUserById(Long id) {
HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("userKey");
com.netflix.hystrix.HystrixCommand.Setter setter = com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(groupKey);
UserCommand userCommand = new UserCommand(setter, restTemplate, id);
// 同步执行获取结果
// return userCommand.execute();
// 异步执行获取结果
Future<User> future = userCommand.queue();
try {
return future.get();
} catch (Exception e) {
logger.info("获取结果发生异常", e);
}
return null;
}
}
注解方式使用HystrixCommand
通过HystrixCommand注解可以更优雅的实现Hystrix命令的定义,如下:
package cn.sh.ribbon.service;
import cn.sh.common.entity.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* @author sh
*/
@Service
public class HelloService {
private static final Logger logger = LoggerFactory.getLogger(HelloService.class);
@Autowired
private RestTemplate restTemplate;
/**
* 通过注解方式获取User
* @param id
* @return
*/
@HystrixCommand
public User findUserById(Long id) {
return restTemplate.getForObject("http://USER-SERVICE/users/{1}", User.class, id);
}
}
上述代码虽然可以优雅的实现Hystrix命令,但是上述获取User的方式只是同步执行的实现,如果需要实现异步执行则需要进行如下改造:
package cn.sh.ribbon.service;
import cn.sh.common.entity.User;
import cn.sh.ribbon.command.UserCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import rx.Observable;
import rx.Subscription;
import rx.functions.Action1;
import java.util.concurrent.Future;
/**
* @author sh
*/
@Service
public class HelloService {
private static final Logger logger = LoggerFactory.getLogger(HelloService.class);
@Autowired
private RestTemplate restTemplate;
/**
* 通过注解方式异步执行获取User
* @param id
* @return
*/
@HystrixCommand
public Future<User> asyncFindUserFutureById(Long id) {
return new AsyncResult<User>() {
@Override
public User invoke() {
return restTemplate.getForObject("http://USER-SERVICE/users/{1}", User.class, id);
}
};
}
}
响应执行
除了传统的同步执行与异步执行之外,我们还可以将HystrixCommand通过Observable来实现响应式执行方式。通过调用observe()和toObservable()可以返回Observable对象, 如下:
Observable<User> observe = userCommand.observe();
Observable<User> observe = userCommand.toObservable();
前者返回的是一个Hot Observable,该命令会在observe调用的时候立即执行,当Observable每次被订阅的时候都会重放它的行为。
后者返回的是一个Cold Observable,toObservable()执行之后,命令不会被立即执行,只有当所有订阅者都订阅他之后才会执行。
HystrixCommand具备了observe()和toObservable()的功能,但是它的实现有一定的局限性,它返回的Observable只能发射一次数据,所以Hystrix提供了另外的一个特殊命令封装HysrtixObservableCommand,通过命令可以发射多次的Observable
响应执行自定义命令
相关代码如下:
package cn.sh.ribbon.command;
import cn.sh.common.entity.User;
import com.netflix.hystrix.HystrixObservableCommand;
import org.springframework.web.client.RestTemplate;
import rx.Observable;
/**
* @author sh
*/
public class UserObservableCommand extends HystrixObservableCommand<User> {
private RestTemplate restTemplate;
private Long id;
public UserObservableCommand (Setter setter, RestTemplate restTemplate, Long id) {
super(setter);
this.restTemplate = restTemplate;
this.id = id;
}
@Override
protected Observable<User> construct() {
return Observable.create(subscriber -> {
if (!subscriber.isUnsubscribed()) {
User user = restTemplate.getForObject("http://USER-SERVICE/users/{1}", User.class, id);
subscriber.onNext(user);
subscriber.onCompleted();
}
});
}
}
响应执行使用注解@HystrixCommand
相关代码如下:
package cn.sh.ribbon.service;
import cn.sh.common.entity.User;
import cn.sh.ribbon.command.UserCommand;
import cn.sh.ribbon.command.UserObservableCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.Subscription;
/**
* @author sh
*/
@Service
public class HelloService {
private static final Logger logger = LoggerFactory.getLogger(HelloService.class);
@Autowired
private RestTemplate restTemplate;
/**
* 使用注解实现响应式命令
* @param id
* @return
*/
@HystrixCommand
public Observable<User> observableGetUserId(Long id) {
return Observable.create(subscriber -> {
if (!subscriber.isUnsubscribed()) {
User user = restTemplate.getForObject("http://USER-SERVICE/users/{1}", User.class, id);
subscriber.onNext(user);
subscriber.onCompleted();
}
});
}
}
使用@HystrixCommand注解实现响应式命令,可以通过observableExecutionMode参数来控制是使用observe()还是toObservable()的执行方式。该参数有下面两种设置方式:
- @HystrixCommand(observableExecutionMode = ObservableExecutionMode.EAGER): EAGER是该参数的模式值,表示使用observe()执行方式。
- @HystrixCommand(observableExecutionMode = ObservableExecutionMode.LAZY): 表示使用toObservable()执行方式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。