• Hystrix


    一、Hystrix源码总结

    Hystrix在底层使用了Spring提供的切面技术:

    • 通过HystrixCommandAspect.java定义了一个切面(该类有@Aspect注解),专门用来处理那些标注了@HystrixCommand的方法
      /**
       * AspectJ aspect to process methods which annotated with {@link HystrixCommand} annotation.
       */
      @Aspect
      public class HystrixCommandAspect {...}
    • 更详细的讲,该类中定义了一个切点。切点是@HystrixCommand。
      @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")
      public void hystrixCommandAnnotationPointcut() {}
    • 而针对该切点,还设置一个环绕函数
      @Around("hystrixCommandAnnotationPointcut()") 
      public Object methodsAnnotatedWithHystrixCommand()
    • 环绕函数中,最关键的一句是execute()。这里会根据executionType有SYNCHRONOUS,ASYNCHRONOUS,OBSERVABLE调用不同逻辑,使用rxjava的观察者模式并最终在这里计算出结果返回。
      result = CommandExecutor.execute(invokable, executionType, metaHolder);
    • 当调用execute()出现失败时,会调用getFallBack()方法。而如果没有设置降级方法则调用父类的getFallBack()方法,父类的getFallBack方法会抛出一个找不到降级方法的异常
      protected T getFallback() {
          throw new RuntimeException("No fallback available.", getExecutionException());
      }

    二、详细解析

    Hystrix在底层使用了Spring提供的切面技术。在HystrixCommandAspect.java文件中可以看到定义的切面:

    /**
     * AspectJ aspect to process methods which annotated with {@link HystrixCommand} annotation.
     */
    @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 metaHolder = metaHolderFactory.create(joinPoint);
            HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
            ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
                    metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();
            
            //result中保留操作的结果,可能是成功操作的返回值也可能是fallback方法的返回值
            Object result;
            try {
                //如果返回的结果使用了observable模式则执行以下代码
                if (!metaHolder.isObservable()) {
                    result = CommandExecutor.execute(invokable, executionType, metaHolder);
                } else {
                //否则执行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;
        }
        ..........
    }

    可以看到在这个类中首先是定义了两个切面,由于我们这里讨论的是HystrixCommand,所以只关注第一个切面,在这个切面里可以看到切点是被HystrixCommand注解的方法,然后对方法的具体增强是在接下来的一个名为methodsAnnotatedWithHystrixCommand()的方法里,具体的流程用注释写在了代码中。

    metaHolder的内容:

    在这里插入图片描述

    可以看到在以上代码中,最重要的便是获取到result具体结果的那一步,由于我们的例子不是使用,所以重点放在:

    result = CommandExecutor.execute(invokable, executionType, metaHolder);

    接下来跳转到CommandExecutor.java中的execute()方法:

    /**
         * Calls a method of {@link HystrixExecutable} in accordance with specified execution type.
         *
         * @param invokable  {@link HystrixInvokable}
         * @param metaHolder {@link MetaHolder}
         * @return the result of invocation of specific method.
         * @throws RuntimeException
         */
        public static Object execute(HystrixInvokable invokable, ExecutionType executionType, MetaHolder metaHolder) throws RuntimeException {
            Validate.notNull(invokable);
            Validate.notNull(metaHolder);
    
            switch (executionType) {
                case SYNCHRONOUS: {
                    return castToExecutable(invokable, executionType).execute();
                }
                case ASYNCHRONOUS: {
                    HystrixExecutable executable = castToExecutable(invokable, executionType);
                    if (metaHolder.hasFallbackMethodCommand()
                            && ExecutionType.ASYNCHRONOUS == metaHolder.getFallbackExecutionType()) {
                        return new FutureDecorator(executable.queue());
                    }
                    return executable.queue();
                }
                case OBSERVABLE: {
                    HystrixObservable observable = castToObservable(invokable);
                    return ObservableExecutionMode.EAGER == metaHolder.getObservableExecutionMode() ? observable.observe() : observable.toObservable();
                }
                default:
                    throw new RuntimeException("unsupported execution type: " + executionType);
            }
        }

    在execute()方法中使用了rxjava的观察者模式并最终在这里计算出结果返回。当出现失败是,会调用GenericCommand.java中的getFallBack()方法,代码如下:

    /**
         * The fallback is performed whenever a command execution fails.
         * Also a fallback method will be invoked within separate command in the case if fallback method was annotated with
         * HystrixCommand annotation, otherwise current implementation throws RuntimeException and leaves the caller to deal with it
         * (see {@link super#getFallback()}).
         * The getFallback() is always processed synchronously.
         * Since getFallback() can throw only runtime exceptions thus any exceptions are thrown within getFallback() method
         * are wrapped in {@link FallbackInvocationException}.
         * A caller gets {@link com.netflix.hystrix.exception.HystrixRuntimeException}
         * and should call getCause to get original exception that was thrown in getFallback().
         *
         * @return result of invocation of fallback method or RuntimeException
         */
        @Override
        protected Object getFallback() {
            final CommandAction commandAction = getFallbackAction();
            if (commandAction != null) {
                try {
                    return process(new Action() {
                        @Override
                        Object execute() {
                            MetaHolder metaHolder = commandAction.getMetaHolder();
                            Object[] args = createArgsForFallback(metaHolder, getExecutionException());
                            return commandAction.executeWithArgs(metaHolder.getFallbackExecutionType(), args);
                        }
                    });
                } catch (Throwable e) {
                    LOGGER.error(FallbackErrorMessageBuilder.create()
                            .append(commandAction, e).build());
                    throw new FallbackInvocationException(unwrapCause(e));
                }
            } else {
                return super.getFallback();
            }
        }

    在这个方法中首先会对是否设置了commandAction进行判断,commandAction就是我们之前所设置的fallback字段指向的方法,如果发现有降级方法,则调用降级方法获取结果,进入process()方法,代码如下:

    /**
         * Executes an action. If an action has failed and an exception is ignorable then propagate it as HystrixBadRequestException
         * otherwise propagate original exception to trigger fallback method.
         * Note: If an exception occurred in a command directly extends {@link java.lang.Throwable} then this exception cannot be re-thrown
         * as original exception because HystrixCommand.run() allows throw subclasses of {@link java.lang.Exception}.
         * Thus we need to wrap cause in RuntimeException, anyway in this case the fallback logic will be triggered.
         *
         * @param action the action
         * @return result of command action execution
         */
        Object process(Action action) throws Exception {
            Object result;
            try {
                result = action.execute();
                flushCache();
            } catch (CommandActionExecutionException throwable) {
                Throwable cause = throwable.getCause();
                if (isIgnorable(cause)) {
                    throw new HystrixBadRequestException(cause.getMessage(), cause);
                }
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Exception) {
                    throw (Exception) cause;
                } else {
                    // instance of Throwable
                    throw new CommandActionExecutionException(cause);
                }
            }
            return result;
        }

    最终在process()方法中获取降级方法执行的结果,而如果没有设置降级方法则调用父类的getFallBack()方法,父类的getFallBack方法会抛出一个找不到降级方法的异常,代码如下:

    protected T getFallback() {
        throw new RuntimeException("No fallback available.", getExecutionException());
    }

    至于何时会跳转到降级方法,则是在AbstractCommand.java中,在这里定义了很多种执行失败的情况,通过rxjava框架的观察者模式对错误进行监听,根据不同的情况会进入不同的处理方法,最终这些处理方法都会调用HystrixCommand.java中的getFallbackObservable()方法,并最终进入上文所述的真正执行fallback方法的代码。

    以上就是对Hystrix降级机制的说明,想要深入理解Hystrix,必须要对rxjava有比较深刻的认识,在Hystrix中大量运用了rxjava。

    参考文献

    版权声明:本文为CSDN博主「栗子栗」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/turbo_zone/article/details/83831992

  • 相关阅读:
    【STM32F429】第5章 ThreadX NetXDUO网络协议栈介绍
    【STM32H7】第5章 ThreadX NetXDUO网络协议栈介绍
    【STM32F407】第5章 ThreadX NetXDUO网络协议栈介绍
    【STM32H7】第25章 ThreadX GUIX复选框Checkbox回调事件处理
    【STM32F429】第23章 ThreadX GUIX复选框Checkbox回调事件处理
    【STM32H7】第4章 初学ThreadX NetXDUO准备工作
    【STM32F429】第4章 初学ThreadX NetXDUO准备工作
    【STM32F407】第4章 初学ThreadX NetXDUO准备工作
    【STM32H7】第3章 PHY芯片和STM32的MAC基础知识
    【STM32F429】第3章 PHY芯片和STM32的MAC基础知识
  • 原文地址:https://www.cnblogs.com/frankcui/p/15249295.html
Copyright © 2020-2023  润新知