Hystrix命令入門使用

主要介紹Hystrix各接口和註解的使用方法。java

建立請求命令

Hystrix命令就是咱們以前所說的HystrixCommand,他用來封裝具體的依賴服務調用邏輯。git

繼承方式實現HystrixCommand

首先經過代碼實現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

經過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();
            }
        });
    }
}

響應執行使用註解@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()的執行方式。該參數有下面兩種設置方式:

  1. @HystrixCommand(observableExecutionMode = ObservableExecutionMode.EAGER): EAGER是該參數的模式值,表示使用observe()執行方式。
  2. @HystrixCommand(observableExecutionMode = ObservableExecutionMode.LAZY): 表示使用toObservable()執行方式。

代碼地址

spring-cloud-example

相關文章
相關標籤/搜索