断路器本身是电路上的一种过载保护装置,当线路中有电器发生短路时,它能够及时的切断故障电路以防止严重后果发生。通过服务熔断(也可以称为断路)、降级、限流(隔离)、异步RPC等手段控制依赖服务的延迟与失败,防止整个服务雪崩。一个断路器可以装饰并且检测了一个受保护的功能调用。根据当前的状态决定调用时被执行还是回退。通常情况下,一个断路器实现三种类型的状态:open、half-open以及closed:

  1. closed状态的调用被执行,事务度量被存储,这些度量是实现一个健康策略所必备的。
  2. 倘若系统健康状况变差,断路器就处在open状态。此种状态下,所有调用会被立即回退并且不会产生新的调用。open状态的目的是给服务器端回复和处理问题的时间。
  3. 一旦断路器进入一个open状态,超时计时器开始计时。如果计时器超时,断路器切换到half-open状态。在half-open状态调用间歇性执行以确定问题是否已解决。如果解决,状态切换回closed状态。

断路器背后的基本思想非常简单。将受保护的函数调用包装在断路器对象中,该对象监视故障。一旦故障达到某个阈值,断路器就会跳闸,并且所有对断路器的进一步调用都会返回错误,而根本不会进行受保护的呼叫。通常,如果断路器跳闸,您还需要某种监控器警报。

如何快速使用Hystrix呢?下面跟着我1234……

1、加入@EnableCircuitBreaker注解

@EnableCircuitBreaker
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClientspublic class DroolsAppApplication {
public static void main(String[] args) {
SpringApplication.run(DroolsAppApplication.class, args);
}
}

Hystrix整体执行过程,首先,Command会调用run方法,如果run方法超时或者抛出异常,且启用了降级处理,则调用getFallback方法进行降级;

2、使用@HystrixCommand注解

 @HystrixCommand(fallbackMethod = "reliable")
public String readingList() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "jinpingmei";
} public String reliable() {
return "you love interesting book";
}

3、添加引用

    compile("org.springframework.cloud:spring-cloud-starter-hystrix")
compile('org.springframework.cloud:spring-cloud-starter-turbine')

4、设置超时时间

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

执行结果如下:

正常应该返回:

你不要喜欢jinpingmei,要喜欢有意思的书;这样使用好舒服啊,@EnableCircuitBreaker这个注解就这么强大吗?

HystrixCommandAspect 通过AOP拦截所有的@HystrixCommand注解的方法,从而使得@HystrixCommand能够集成到Spring boot中,

HystrixCommandAspect的关键代码如下:

1.方法 hystrixCommandAnnotationPointcut() 定义拦截注解HystrixCommand

2.方法 hystrixCollapserAnnotationPointcut()定义拦截注解HystrixCollapser

3.方法methodsAnnotatedWithHystrixCommand(…)通过@Around(…)拦截所有HystrixCommand和HystrixCollapser注解的方法。详细见方法注解

@Aspect
public class HystrixCommandAspect { private static final Map<HystrixPointcutType, MetaHolderFactory> META_HOLDER_FACTORY_MAP; static {
META_HOLDER_FACTORY_MAP = ImmutableMap.<HystrixPointcutType, MetaHolderFactory>builder()
.put(HystrixPointcutType.COMMAND, new CommandMetaHolderFactory())
.put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory())
.build();
} @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)") public void hystrixCommandAnnotationPointcut() {
} @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
public void hystrixCollapserAnnotationPointcut() {
} @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
Method method = getMethodFromTarget(joinPoint);
Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
"annotations at the same time");
}
MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();
Object result;
try {
result = CommandExecutor.execute(invokable, executionType, metaHolder);
} catch (HystrixBadRequestException e) {
throw e.getCause();
}
return result;
}

那么HystrixCommandAspect是如何初始化,是通过HystrixCircuitBreakerConfiguration实现的

@Configuration
public class HystrixCircuitBreakerConfiguration { @Bean
public HystrixCommandAspect hystrixCommandAspect() {
return new HystrixCommandAspect();
}

那么谁来触发HystrixCircuitBreakerConfiguration执行初始化

先看spring-cloud-netflix-core**.jar包的spring.factories里有这段配置,是由注解EnableCircuitBreaker触发

org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\
org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration

那么@EnableCircuitBreaker如何触发HystrixCircuitBreakerConfiguration
通过源码查看,此类通过@Import初始化EnableCircuitBreakerImportSelector类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableCircuitBreakerImportSelector.class)
public @interface EnableCircuitBreaker {
}

EnableCircuitBreakerImportSelector是SpringFactoryImportSelector子类。此类在初始化后,会执行selectImports(AnnotationMetadata metadata)的方法。此方法会根据注解启动的注解(这里指@EnableCircuitBreaker)从spring.factories文件中获取其配置需要初始化@Configuration类(这里是org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration),从而最终初始化HystrixCommandAspect 类,从而实现拦截HystrixCommand的功能

以上就是通过@EnableCircuitBreake可以开启Hystrix的原理。Hystrix用到了观察者模式AbstractCommand.executeCommandAndObserve()模式,下次我们来深入说一下观察者模式。欢迎拍砖!

Spring Boot中使用断路器的更多相关文章

  1. spring boot(三):Spring Boot中Redis的使用

    spring boot对常用的数据库支持外,对nosql 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结 ...

  2. Spring Boot中的事务管理

    原文  http://blog.didispace.com/springboottransactional/ 什么是事务? 我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多步操作的结合 ...

  3. Spring Boot中的注解

    文章来源:http://www.tuicool.com/articles/bQnMra 在Spring Boot中几乎可以完全弃用xml配置文件,本文的主题是分析常用的注解. Spring最开始是为了 ...

  4. 在Spring Boot中使用Https

    本文介绍如何在Spring Boot中,使用Https提供服务,并将Http请求自动重定向到Https. Https证书 巧妇难为无米之炊,开始的开始,要先取得Https证书.你可以向证书机构申请证书 ...

  5. Spring Boot中使用Swagger2构建强大的RESTful API文档

    由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这 ...

  6. Dubbo在Spring和Spring Boot中的使用

    一.在Spring中使用Dubbo 1.Maven依赖 <dependency> <groupId>com.alibaba</groupId> <artifa ...

  7. springboot(十一):Spring boot中mongodb的使用

    mongodb是最早热门非关系数据库的之一,使用也比较普遍,一般会用做离线数据分析来使用,放到内网的居多.由于很多公司使用了云服务,服务器默认都开放了外网地址,导致前一阵子大批 MongoDB 因配置 ...

  8. springboot(三):Spring boot中Redis的使用

    spring boot对常用的数据库支持外,对nosql 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结 ...

  9. Spring Boot中使用Swagger2构建API文档

    程序员都很希望别人能写技术文档,自己却很不愿意写文档.因为接口数量繁多,并且充满业务细节,写文档需要花大量的时间去处理格式排版,代码修改后还需要同步修改文档,经常因为项目时间紧等原因导致文档滞后于代码 ...

随机推荐

  1. easy-ui treegrid 实现分页 并且添加自定义checkbox

    首先第一点easy-ui  treegrid 对分页没有好的实现, 因为在分页的过程中是按照 根节点来分页的  后台只能先按照 根节点做分页查询  再将子节点关联进去, 这样才能将treegrid 按 ...

  2. win10 64位 安装scrapy

    在学习python时,不可避免下载了Anaconda,当我打算写爬虫时,urllib,requests,selenium,pyspider都已经安装好了,可以直接使用了,但是有一天我想要使用scrap ...

  3. Linux学习---指针运算、修饰符(const、volatile、typedef)及、运算符(++、--、+、-)

    const:常量.只读[不能变] char *p; const char *p; [T] 字符串内容可以为“hello world”或“aaa”,但只读(不可修改) char const *p; ch ...

  4. WebServices 注解汇总

    Web Service 元数据注释 @WebService 1.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service.缺省值为 Java 类的 ...

  5. 使用django我的第一个简单项目流程

    项目概述:本项目实现的是员工提交需要审批的事情给老板(例如请假事件.某些具体事务需要老板确认事件等),老板确认或者拒绝该事件,员工登录员工自己的页面可以查询响应的状态信息. 代码实现概略:需要创建两个 ...

  6. POJ - 3984 迷宫问题 bfs解法

    #include<stdio.h> #include<string.h> #include<algorithm> #include<stack> usi ...

  7. python的无限循环及退出

    题目要求如下: 1 循环验证用户输入的用户名与密码 2 认证通过后,运行用户重复执行命令 3 当用户输入命令为quit时,则退出整个程序  代码如下 person={'name':'Helen','p ...

  8. FPGA中分数分频器的实现代码

    module clkFracDiv( output reg clkout, input rstn, input refclk, :] fenzi, :] fenmu ); :] rstn_syn; : ...

  9. HAProxy详细中文用法详解

    一.HAProxy简介 (1)HAProxy 是一款提供高可用性.负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费.快速并且可靠的一种解决方案. HAProx ...

  10. python yield 关键字

    最近看代码看到python里面的yield关键字,和我之前接触的语言好像都没有来着,我就查了查它的含义,大概理解如下: >>> def createGenerator(): ... ...