Spring cloud Hystrix使用@HystrixCommand使用Hystrix組件及@EnableCircuitBreaker原理介紹


通過@HystrixCommand注解實現在Spring Cloud使用Hystrix組件相關的工程

  • cloud-registration-center:注冊中心
  • cloud-service-hystrix: 作為服務方的工程
  • cloud-consumer-hystrix:通過hystrix調用cloud-service-hystrix的接口

 

1.cloud-service-hystrix

作為服務方的工程,此工程比較簡單,

bootstrap-hystrix.yml

只列出部分內容

spring: application: # 本服務注冊到注冊到服務器的名稱, 這個名稱就是后面調用服務時的服務標識符 name: cloud-hystrix-service ….

 

 

2.SimpleCtl:提供服務的Control類

@RestController public class SimpleCtl { private AtomicInteger count = new AtomicInteger(); private AtomicInteger sleepCount = new AtomicInteger(); @RequestMapping(value="/hystrix/simp le") public String hystrixClientCall(@RequestParam("time") long time){ int newCount = count.incrementAndGet(); return "time " + time + " hystrix" + newCount + ": " + ThreadLocalRandom.current().nextInt(1000); } …… }

 

3.cloud-consumer-hystrix

通過hystrix調用cloud-service-hystrix的接口

 

pom.xml:只列出關鍵的jar <!-- hystrix -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>

 

 

  bootstrap-hystrix-simple.yml屬性配置

# port server: port: 12083 spring: application: # 本服務注冊到注冊到服務器的名稱, 這個名稱就是后面調用服務時的服務標識符 name: cloud-consumer-hystrix eureka: client: serviceUrl: # 服務器注冊/獲取服務器的zone defaultZone: http://127.0.0.1:10761/eureka/
 instance: prefer-ip-address: true

 

 

 

4.MyHystrixClient

 

功能:通過RestTemplate調用服務的接口

  • @HystrixCommand:此注解表示此方法是hystrix方法,其中fallbackMethod定義回退方法的名稱
  • String myFallback(long p, Throwable e) :HystrixCommand的回退方法,此方法必須和hystrix的執行方法在相同類中。可以把HystrixCommand的執行參數和執行失敗的異常傳入回退方法中
@Service public class MyHystrixClient { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "myFallback") public String simpleHystrixClientCall(long time) { return restTemplate.getForEntity("http://CLOUD-HYSTRIX-SERVICE/hystrix/simple?time=" + time, String.class).getBody(); } /** * 方法simpleHystrixClientCall的回退方法,可以指定將hystrix執行失敗異常傳入到方法中 * @param p ystrix執行失敗的傳入方法的請求 * @param e hystrix執行失敗的異常對象 * @return
     */ String myFallback(long p, Throwable e) { return "Execute raw fallback: access service fail , req= " + p + " reason = " + e; }

 

 @HystrixCommand:其他參數說明

 

 

 public @interface HystrixCommand { // HystrixCommand 命令所屬的組的名稱:默認注解方法類的名稱
            String groupKey() default ""; // HystrixCommand 命令的key值,默認值為注解方法的名稱
            String commandKey() default ""; // 線程池名稱,默認定義為groupKey
            String threadPoolKey() default ""; // 定義回退方法的名稱, 此方法必須和hystrix的執行方法在相同類中
            String fallbackMethod() default ""; // 配置hystrix命令的參數
            HystrixProperty[] commandProperties() default {}; // 配置hystrix依賴的線程池的參數
             HystrixProperty[] threadPoolProperties() default {}; // 如果hystrix方法拋出的異常包括RUNTIME_EXCEPTION,則會被封裝HystrixRuntimeException異常。我們也可以通過此方法定義哪些需要忽略的異常
            Class<? extends Throwable>[] ignoreExceptions() default {}; // 定義執行hystrix observable的命令的模式,類型詳細見ObservableExecutionMode
            ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER; // 如果hystrix方法拋出的異常包括RUNTIME_EXCEPTION,則會被封裝HystrixRuntimeException異常。此方法定義需要拋出的異常
            HystrixException[] raiseHystrixExceptions() default {}; // 定義回調方法:但是defaultFallback不能傳入參數,返回參數和hystrix的命令兼容
            String defaultFallback() default ""; }

 

 

SimpleCtl

 

通過Control的方法調用MyHystrixClient的方法,返回執行結果

@RestController public class SimpleCtl { @Autowired private MyHystrixClient myHystrixClient; @RequestMapping(value="/hystrix/simple") public String simpleClientCall(){ return "rsp: " + myHystrixClient.simpleHystrixClientCall(System.currentTimeMillis()); } }

 

 

配置Hystrix的自定義參數

 
        

以下時配置hystrix的線程池的大小,其他的配置見Spring cloud系列九 Hystrix的配置屬性優先級和詳解

 
        

application-hystrix-simple.yml

 
        
# 配置hystrix的參數 hystrix: threadpool: # default: 默認參數,作用的所有的hystrix的客戶端 default: coreSize: 10

 

 

 啟動類HystrixSimpleCloudConsumerApplication

  • @EnableCircuitBreaker :啟動斷路器
  • 方法RestTemplate restTemplate():初始化RestTemplate 對象,並使用 @LoadBalanced作負載均衡
@SpringBootApplication @EnableCircuitBreaker @EnableEurekaClient // 配置本應用將使用服務注冊和服務發現
public class HystrixSimpleCloudConsumerApplication { public static void main(String[] args) { args = new String[1]; args[0] = "--spring.profiles.active=hystrix-simple"; SpringApplication.run(HystrixSimpleCloudConsumerApplication.class, args); } /** * 初始RestTemplate * @return
     */ @LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); } /** * 使用fastjson做為json的解析器 * @return
     */ @Bean public HttpMessageConverters fastJsonHttpMessageConverters() { FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); fastConverter.setFastJsonConfig(fastJsonConfig); HttpMessageConverter<?> converter = fastConverter; return new HttpMessageConverters(converter); } }

 

 

 

6.測試

啟動服務

啟動工程cloud-registration-center:配置中心地址:http://127.0.0.1:10761 
啟動工程cloud-service-hystrix的HystrixCloudServiceApplication的啟動類 
啟動工程cloud-consumer-hystrix的HystrixSimpleCloudConsumerApplication的啟動類

測試一 
執行cloud-consumer-hystrix的調用cloud-service-hystrix服務的接口 
在瀏覽器中運行URL: http://127.0.0.1:12083//hystrix/simple 
返回:

"rsp: \"time 1511015252093 hystrix1: 434\""

 

測試二 
停止cloud-service-hystrix服務 
執行cloud-consumer-hystrix的調用cloud-service-hystrix服務的接口 
在瀏覽器中運行URL: http://127.0.0.1:12083//hystrix/simple 
返回:

 

"rsp: Execute raw fallback: access service fail , req= 1511103681411 reason = com.netflix.hystrix.exception.HystrixTimeoutException"

 

 說明fallback方法被執行了

 

 

測試三 
修改application-hystrix-simple.yml 中的hystrix的線程池的線程數量為0,

# 配置hystrix的參數
hystrix:
  threadpool:
    # default: 默認參數,作用的所有的hystrix的客戶端
    default:
      coreSize: 0

 

重啟cloud-service-hystrix和cloud-consumer-hystrix, 
執行http://127.0.0.1:12083//hystrix/simple 
提示執行hystrix方法失敗,說明我們的配置啟作用了

 

@EnableCircuitBreaker的原理

 

在啟動類HystrixSimpleCloudConsumerApplication中使用@EnableCircuitBreaker + @HystrixCommand 注解啟動Hystrix斷路器的功能。本節介紹此注解的原理

7.1 HystrixCommandAspect

HystrixCommandAspect 通過AOP攔截所有的@HystrixCommand注解的方法,從而使得@HystrixCommand能夠集成到Spring boot中

HystrixCommandAspect的關鍵代碼如下:

  • 1 方法 hystrixCommandAnnotationPointcut() 定義攔截注解HystrixCommand
  • 2 方法 hystrixCollapserAnnotationPointcut()定義攔截注解HystrixCollapser
  • 3 方法methodsAnnotatedWithHystrixCommand(…)通過@Around(…)攔截所有HystrixCommand和HystrixCollapser注解的方法。詳細見方法注解
@Aspect public class HystrixCommandAspect { @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 method = getMethodFromTarget(joinPoint); Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint); // 只有被HystrixCommand和HystrixCollapser注解的方法才執行后續操作
        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"); } // 根據攔截方法的注解HystrixCommand或HystrixCollapser分別獲取CommandMetaHolderFactory或者CollapserMetaHolderFactory類
        MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method)); // 將攔截方法封裝到MetaHolder中
        MetaHolder metaHolder = metaHolderFactory.create(joinPoint); // 根據metaHolder生成相應的HystrixCommand,包含生成hystrix執行時需要的配置信息,這些配置信息來自默認配置或我們自定義的屬性
        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder); ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ? metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType(); Object result; try { // 根據是否是Observable執行CommandExecutor.execute()方法,executeObservable最后也會執行CommandExecutor.execute()方法
            if (!metaHolder.isObservable()) { result = CommandExecutor.execute(invokable, executionType, metaHolder); } else { result = executeObservable(invokable, executionType, metaHolder); } } catch (HystrixBadRequestException e) { throw e.getCause() != null ? e.getCause() : e; } catch (HystrixRuntimeException e) { throw hystrixRuntimeExceptionToThrowable(metaHolder, e); } return result; } …. }

 

 

@EnableCircuitBreaker 和 EnableCircuitBreakerImportSelector

那么誰來觸發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的原理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM