主要介紹Hystrix各接口和註解的使用方法。java
Hystrix命令就是咱們以前所說的HystrixCommand,他用來封裝具體的依賴服務調用邏輯。git
首先經過代碼實現HystrixCommandgithub
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,咱們便可以實現請求的同步執行也能夠實現異步執行,相關代碼以下:web
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註解能夠更優雅的實現Hystrix命令的定義,以下:spring
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對象, 以下:async
Observable<User> observe = userCommand.observe(); Observable<User> observe = userCommand.toObservable();
前者返回的是一個Hot Observable,該命令會在observe調用的時候當即執行,當Observable每次被訂閱的時候都會重放它的行爲。ide
後者返回的是一個Cold Observable,toObservable()執行以後,命令不會被當即執行,只有當全部訂閱者都訂閱他以後纔會執行。this
HystrixCommand具有了observe()和toObservable()的功能,可是它的實現有必定的侷限性,它返回的Observable只能發射一次數據,因此Hystrix提供了另外的一個特殊命令封裝HysrtixObservableCommand,經過命令能夠發射屢次的Observable.net
相關代碼以下:
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(); } }); } }
相關代碼以下:
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()的執行方式。該參數有下面兩種設置方式: