ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Hystrix - Hystrix源码解析

2021-09-09 22:31:24  阅读:149  来源: 互联网

标签:Hystrix throw 源码 result 解析 方法 method HystrixCommand metaHolder


一、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

 

标签:Hystrix,throw,源码,result,解析,方法,method,HystrixCommand,metaHolder
来源: https://www.cnblogs.com/frankcui/p/15249295.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有