Spring cloud Hystrix注解初始化源码过程解读

 更新时间:2023年12月21日 14:34:53   作者:福  
这篇文章主要为大家介绍了Hystrix初始化部分,我们从源码的角度分析一下@EnableCircuitBreaker以及@HystrixCommand注解的初始化过程,有需要的朋友可以借鉴参考下,希望能够有所帮助

从@EnableCircuitBreaker入手

我们是通过在启动类添加@EnableCircuitBreaker注解启用Hystrix的,所以,源码解析也要从这个注解入手。

该注解已经被标了@Deprecated了,不过,挡不住......

Spring关于@Enablexxxx注解的套路:通过@Import注解引入了EnableCircuitBreakerImportSelector.class:

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

}

跟踪EnableCircuitBreakerImportSelector,继承自SpringFactoryImportSelector<EnableCircuitBreaker>,注意SpringFactoryImportSelector类的泛型类型为EnableCircuitBreaker:

@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableCircuitBreakerImportSelector extends SpringFactoryImportSelector&lt;EnableCircuitBreaker&gt; {

    @Override
    protected boolean isEnabled() {
        return getEnvironment().getProperty("spring.cloud.circuit.breaker.enabled", Boolean.class, Boolean.TRUE);
    }

}

看一下类图:

属性annotationClass通过GenericTypeResolver.resolveTypeArgument方法获取当前对象的泛型参数的具体类型,现在我们知道是EnableCircuitBreaker(在org.springframework.cloud.client.circuitbreaker包下)。

public abstract class SpringFactoryImportSelector<T>
        implements DeferredImportSelector, BeanClassLoaderAware, EnvironmentAware {
    private final Log log = LogFactory.getLog(SpringFactoryImportSelector.class);
    private ClassLoader beanClassLoader;
    private Class<T> annotationClass;
    private Environment environment;
    @SuppressWarnings("unchecked")
    protected SpringFactoryImportSelector() {
        this.annotationClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(this.getClass(),
                SpringFactoryImportSelector.class);
    }

@Import注解我们前面做过详细分析了,实现了DeferredImportSelector接口表示延迟加载全限定名称为selectImports方法返回的类。看selectImports方法:

@Override
    public String[] selectImports(AnnotationMetadata metadata) {
        //Enable参数没有打开的话就不加载
        if (!isEnabled()) {
            return new String[0];
        }
        AnnotationAttributes attributes = AnnotationAttributes
                .fromMap(metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
        Assert.notNull(attributes, "No " + getSimpleName() + " attributes found. Is " + metadata.getClassName()
                + " annotated with @" + getSimpleName() + "?");
        // Find all possible auto configuration classes, filtering duplicates
        //SPI机制调用spring.factories文件下的EnableCircuitBreaker
        List<String> factories = new ArrayList<>(new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
        if (factories.isEmpty() && !hasDefaultFactory()) {
            throw new IllegalStateException("Annotation @" + getSimpleName()
                    + " found, but there are no implementations. Did you forget to include a starter?");
        }
        if (factories.size() > 1) {
            // there should only ever be one DiscoveryClient, but there might be more than
            // one factory
            this.log.warn("More than one implementation " + "of @" + getSimpleName()
                    + " (now relying on @Conditionals to pick one): " + factories);
        }
        return factories.toArray(new String[factories.size()]);
    }

selectImports方法的主要功能就是调用SpringFactoriesLoader.loadFactoryNames方法,该方法的目的是通过SPI机制读取spring.factories文件中的org.springframework.cloud.client.circuitbreaker相关配置,返回。

返回的信息是类全限定名,从selectImports方法作用可知,这些类会加载到Spring Ioc容器中。

org.springframework.cloud.client.circuitbreaker在spring-cloud-netflix-hystrix-2.2.10.RELEASE包下:

所以该配置下的org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration会被调用并加载到Spring IoC容器中。

HystrixCircuitBreakerConfiguration

跟踪配置类HystrixCircuitBreakerConfiguration:

/**
 * @author Spencer Gibb
 * @author Christian Dupuis
 * @author Venil Noronha
 */
@Configuration(proxyBeanMethods = false)
public class HystrixCircuitBreakerConfiguration {
    @Bean
    public HystrixCommandAspect hystrixCommandAspect() {
        return new HystrixCommandAspect();
    }
    @Bean
    public HystrixShutdownHook hystrixShutdownHook() {
        return new HystrixShutdownHook();
    }

注入了一个叫HystrixCommandAspect 的bean,从名字上看,应该是关于HystrixCommand的切面,用到了AOP。其实也容易理解,加了@HystrixCommand注解的方法的执行逻辑发生了变化:方法增强了执行时长是否超时、执行是否成功(是否返回异常)、超时或异常的情况下调用fallback......方法功能的增强正是AOP的强项。

继续跟踪HystrixCommandAspect 类。

HystrixCommandAspect

打开代码,首先是非常熟悉的@Aspect注解:

@Aspect
public class HystrixCommandAspect {

表明当前类是AOP的切面。

继续看代码:

@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 {

添加了针对注解HystrixCommand的切点,以及针对该切点的环绕增强方法methodsAnnotatedWithHystrixCommand。

最终的熔断、限流、服务降级功能,都是在这个methodsAnnotatedWithHystrixCommand方法里实现的,继续向下研究这个方法的代码逻辑,需要RxJava背景知识做支撑。

以上就是Spring cloud Hystrix注解初始化源码过程解读的详细内容,更多关于Spring cloud Hystrix注解初始化的资料请关注脚本之家其它相关文章!

相关文章

  • struts2+jsp+jquery+Jcrop实现图片裁剪并上传实例

    struts2+jsp+jquery+Jcrop实现图片裁剪并上传实例

    本篇文章主要介绍了struts2+jsp+jquery+Jcrop实现图片裁剪并上传实例,具有一定的参考价值,有兴趣的可以了解一下。
    2017-01-01
  • springboot如何自定义pom内子依赖版本

    springboot如何自定义pom内子依赖版本

    这篇文章主要介绍了springboot如何自定义pom内子依赖版本问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Java实现一个达达租车系统的步骤详解

    Java实现一个达达租车系统的步骤详解

    这篇文章主要给大家介绍了利用Java实现一个达达租车系统的步骤,文中给出了详细的实现思路和示例代码,并在文末给出了完整的源码供大家学习下载,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-04-04
  • 在本地用idea连接虚拟机上的hbase集群的实现代码

    在本地用idea连接虚拟机上的hbase集群的实现代码

    这篇文章主要介绍了在本地用idea连接虚拟机上的hbase集群的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Java21之虚拟线程用法实践指南及常见问题

    Java21之虚拟线程用法实践指南及常见问题

    虚拟线程是Java19中作为预览功能提出,21中正式完成的轻量级线程,旨在减少编写易于观察的高吞吐量的并发程序的工作量,这篇文章主要介绍了Java21之虚拟线程用法的相关资料,需要的朋友可以参考下
    2026-01-01
  • @WebFilter在SpringBoot无效的原因分析和解决方案

    @WebFilter在SpringBoot无效的原因分析和解决方案

    使用Ruoyi的demo部署成功后,发现js、css等静态文件都进入了过滤器,但是发现静态文件没有使用浏览器缓存,新建BrowserCacheFilter.java并增加@WebFilter处理,应用自动重启后发现@WebFilter无效,所以本文给大家介绍了@WebFilter在SpringBoot无效的原因分析和解决方案
    2024-03-03
  • Dwr3.0纯注解(纯Java Code配置)配置与应用浅析二之前端调用后端

    Dwr3.0纯注解(纯Java Code配置)配置与应用浅析二之前端调用后端

    我们讲到了后端纯Java Code的Dwr3配置,完全去掉了dwr.xml配置文件,但是对于使用注解的类却没有使用包扫描,而是在Servlet初始化参数的classes里面加入了我们的Service组件的声明暴露,对于这个问题需要后面我们再细细研究下这篇文章,主要分析介绍前端怎么直接调用后端
    2016-04-04
  • JavaOOP封装实例解读

    JavaOOP封装实例解读

    封装通过private限制属性访问,提供get/set方法控制数据读写,确保值合法,示例中Student类属性私有,Test类需调用set方法赋值并验证,get方法获取值,实现数据隐藏与安全操作
    2025-09-09
  • 新版idea工具栏菜单展开与合并显示方式

    新版idea工具栏菜单展开与合并显示方式

    文章介绍了如何在新版IDEA中调整工具栏菜单的显示方式,通过取消勾选设置中的某个选项,可以使菜单展开更加方便
    2025-01-01
  • win11 idea shift+F6快捷键失效问题解决方案

    win11 idea shift+F6快捷键失效问题解决方案

    这篇文章主要介绍了win11 idea shift+F6快捷键失效问题,本文给大家分享最新解决方案,需要的朋友可以参考下
    2023-08-08

最新评论