透过源码学习设计模式4—HystrixCommand和命令模式

2019-07-31 16:05:52 浏览数 (1)

简介:

在面对对象编程中,命令模式是一种行为模式,其中对象用于封装执行动作或稍后触发事件所需的所有信息。这些信息包括方法名称,拥有该方法的对象以及方法参数的值。命令模式也支持可撤销操作。

命令模式包括4个角色:

Command:定义命令的统一接口

ConcreteCommand:Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。

Receiver:命令的实际执行者

Invoker:命令的请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。

命令模式有如下优点:

1.降低对象之间的耦合度(将发出请求的对象和执行请求的对象解耦,即将调用者和执行者进行解耦)

2.新的命令可以很容易地加入到系统中。

3.可以比较容易地设计一个组合命令。

4.调用同一方法实现不同的功能

缺点:

可能会导致某些系统有过多的具体命令类。

Hystrix

Hystrix命令模式封装了命令运行逻辑(run)和服务调用失败时回退逻辑(getFallback)。其command抽象类是hystrixcommand,用于包装执行具有潜在风险功能的代码(通常指通过网络进行的服务调用),具备容错和延时,统计和性能指标捕获,断路器和舱壁功能。

该命令本质上是一个阻塞命令,但如果与observe()一起使用,则提供一个可观察的facade。

此模式的详情如下:

  1. 构造Hystrix命令对象,并调用run方法
  2. Hystrix将检查断路器开关是否打开,如果打开,则调用回退方法
  3. 如果断路器开关关闭,Hystrix将检查当前服务的线程池,看是否可以接受新请求。如果线程池已满,则调用回退方法
  4. 如果线程池可以接受新请求,那么Hystrix可以调用run方法来执行run逻辑
  5. 如果run执行失败,则调用回退方法并将健康状态返回到Hystrix指标
  6. 如果run执行超时,则调用回退方法并将健康状况返回到Hystrix指标
  7. 如果run成功执行,则返回正常结果
  8. 如果回退方法成功执行,它将返回回退执行结果
  9. 如果回退方法执行失败,则抛出异常

伪代码示例子

那是否使用命令模式,这两者有什么区别呢?我们通过一些伪代码来帮助理解.

有hystrixcommand之前:

代码语言:javascript复制
public class SimpleHystrix {
  private RestService restService;
  private HttpClientService httpClientService;
  private OkHttpService  okHttpService;
    public void call(String callName) {
        if (callName.equals("httpclient")) {
httpClientService.do();
       } else if (callName.equals("okhttpclient")) {
okHttpService.do();
        } else if (callName.equals("restClient")) {
restService.do();
        }
    }
}
public class SimpleHystrixRun {
    public static void main(String[] args) {
        SimpleHystrix simpleHystrix = new SimpleHystrix();
        simpleHystrix.call("httpclient");
        simpleHystrix.call("okhttpclient");
        simpleHystrix.call("restClient");
    }
}

这里需要根据指令来调用对象的方法,如果需要新增command类型,那么就需要在SimpleHystrix里增加判断,这样SimpleHystrix始终要关注需要调用的外部服务,如果新增服务时需要改动代码,这样违背了面向接口编程的原则,同时代码也较难维护。

有HystrixCommand之后:

如图示,RibbonCommand继承HystrixCommand,它有三个子类

代码语言:javascript复制
public class SimpleHystrix {
    private SimpleHystrixCommand simpleHystrixCommand;
    public void setSimpleHystrixCommand(SimpleHystrixCommand simpleHystrixCommand) {
        this.simpleHystrixCommand = simpleHystrixCommand;
    }
    public void call() {
        simpleHystrixCommand.execute();
    }
}
//SimpleHystrixRun为client
public class SimpleHystrixRun {
    public static void main(String[] args) {
// 这里service为命令的实际执行者,即Receiver
       RestService restService= newRestService();
//simpleHystrix为命令的请求者,即Invoker
        SimpleHystrix simpleHystrix = new SimpleHystrix();
//HttpClientRibbonCommand等是具体命令, ConcreteCommand
        simpleHystrix.setSimpleHystrixCommand(new HttpClientRibbonCommand(restService));
        simpleHystrix.call();
        HttpClientServicehttpClientService= newHttpClientService();
        simpleHystrix.setSimpleHystrixCommand(new OkHttpRibbonCommand(httpClientService));
        simpleHystrix.call();
        OkHttpService okHttpService= newOkHttpService();
        simpleHystrix.setSimpleHystrixCommand(new RestClientRibbonCommand(okHttpService));
        simpleHystrix.call();
    }
}

具体执行逻辑在Command中实现,如

ConcreteCommand:

代码语言:javascript复制
public class HttpClientRibbonCommand implements SimpleHystrixCommand {
   @Override
   public void execute() {
    //do things
   }
}

将服务的实现封装到一个对象委托出去,由命令对象来实现具体的调用。只需要增加一个继承Command的类,然后在execute方法实现对应服务的调用以及其他操作即可,无需侵入业务代码。

java达人

0 人点赞