Spring Boot中如何使用断路器详解

作者:只喝牛奶的杀手 时间:2022-03-03 06:34:49 

前言

随着使用 Spring 进行开发的个人和企业越来越多,Spring 也慢慢从一个单一简洁的小框架变成一个大而全的开源软件,Spring 的边界不断的进行扩充,到了后来 Spring 几乎可以做任何事情了,市面上主流的开源软件、中间件都有 Spring 对应组件支持,人们在享用 Spring 的这种便利之后,也遇到了一些问题。

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

  • closed状态的调用被执行,事务度量被存储,这些度量是实现一个健康策略所必备的。

  • 倘若系统健康状况变差,断路器就处在open状态。此种状态下,所有调用会被立即回退并且不会产生新的调用。open状态的目的是给服务器端回复和处理问题的时间。

  • 一旦断路器进入一个open状态,超时计时器开始计时。如果计时器超时,断路器切换到half-open状态。在half-open状态调用间歇性执行以确定问题是否已解决。如果解决,状态切换回closed状态。

Spring Boot中如何使用断路器详解

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

Spring Boot中如何使用断路器详解

如何快速使用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方法进行降级;

Spring Boot中如何使用断路器详解 

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

执行结果如下:

Spring Boot中如何使用断路器详解 

正常应该返回:

Spring Boot中如何使用断路器详解 

你不要喜欢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的功能

来源:http://www.cnblogs.com/viaiu/p/9534153.html

标签:spring,boot,断路器
0
投稿

猜你喜欢

  • c# 类成员的可访问性代码详解

    2022-03-14 22:43:59
  • Java对XML文件增删改查操作示例

    2021-10-28 08:46:29
  • spring-cloud-gateway动态路由的实现方法

    2021-07-25 15:24:37
  • Java流式操作之Collectors工具类操作指南

    2022-12-01 01:25:55
  • C#写入XML文档

    2022-03-21 18:08:33
  • winform中的ListBox和ComboBox绑定数据用法实例

    2023-09-24 05:02:13
  • Java JDK11基于嵌套的访问控制的实现

    2021-07-11 10:02:05
  • C#中的那些警告该如何去除(完全去除C#警告)

    2023-09-07 20:55:53
  • Spring的AOP极简入门

    2023-07-10 22:24:32
  • Flutter之Timer实现短信验证码获取60s倒计时功能的代码

    2023-07-20 20:00:30
  • SpringBoot程序的打包与运行的实现

    2023-11-29 15:51:27
  • java解析多层嵌套json字符串问题

    2023-08-26 11:08:33
  • 详解java模板和回调机制

    2023-08-13 15:33:46
  • java.lang.UnsatisfiedLinkError: %1 不是有效的Win32应用程序错误解决

    2022-06-14 23:21:51
  • C#实现工厂方法模式

    2023-12-10 05:17:37
  • C# ping网络IP 实现网络状态检测的方法

    2023-01-11 14:31:05
  • 浅析java 10中的var关键字用法

    2021-12-23 15:18:17
  • Android屏幕旋转 处理Activity与AsyncTask的最佳解决方案

    2023-03-22 07:02:50
  • java控制台实现学生信息管理系统(集合版)

    2023-11-11 14:16:52
  • 如何在MyBatis中实现DataSource

    2021-11-29 13:49:48
  • asp之家 软件编程 m.aspxhome.com