不同于SpringBoot中常用spring.factories文件中配置@EnableAutoConfigration做自动装配,SpringCloud中比较常见的组件引入方式是通过@EnableXXX注解方式引入。Hystrix的引入方式是@EnableCircuitBreaker或则@EnableHystrix

    1. @Target(ElementType.TYPE)
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Inherited
    4. @EnableCircuitBreaker// 引用
    5. public @interface EnableHystrix {
    6. }
    7. @Target(ElementType.TYPE)
    8. @Retention(RetentionPolicy.RUNTIME)
    9. @Inherited
    10. @Import(EnableCircuitBreakerImportSelector.class) // import导入
    11. public @interface EnableCircuitBreaker {
    12. }

    EnableCircuitBreakerImportSelectorSpring中ImportSelector的实现类,用于引入配置类.
    在SpringCloud中做了一个抽象实现,SpringFactoryImportSelector<T>,Euraka客户端和Hystrix都是通过这个方式引入。
    image.png
    SpringFactoryImportSelector

    public abstract class SpringFactoryImportSelector<T>
            implements DeferredImportSelector, BeanClassLoaderAware, EnvironmentAware {
    
        private ClassLoader beanClassLoader;
        private Class<T> annotationClass;
        private Environment environment;
    
        protected SpringFactoryImportSelector() {
            // 获取实现类上泛型参数,如@EnableCircuitBreaker
            this.annotationClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(this.getClass(), SpringFactoryImportSelector.class);
        }
    
        @Override
        public String[] selectImports(AnnotationMetadata metadata) {
            if (!isEnabled()) {
                return new String[0];
            }
            //
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
    
            // 从spring.factories文件中加载指定的配置类
            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?");
            }
            // 配置类全路径
            return factories.toArray(new String[factories.size()]);
        }
    }
    

    子类的作用就是指定特定的泛型以便于加载配置类

    @Order(Ordered.LOWEST_PRECEDENCE - 100)
    public class EnableCircuitBreakerImportSelector extends
        SpringFactoryImportSelector<EnableCircuitBreaker> {
        @Override
        protected boolean isEnabled() {
            return getEnvironment().getProperty("spring.cloud.circuit.breaker.enabled", Boolean.class, Boolean.TRUE);
        }
    }
    

    这里的泛型参数就是@EnableCircuitBreaker,同时可以看到在spring.factories配置文件中存在这样的配置
    image.png
    在启动类上标注了@EnableCircuitBreaker后,就会加载配置类HystrixCircuitBreakerConfiguration

    @Configuration
    public class HystrixCircuitBreakerConfiguration {
        // 熔断操作的切面配置
        @Bean
        public HystrixCommandAspect hystrixCommandAspect() {
            return new HystrixCommandAspect();
        }
        // 钩子方法
        @Bean
        public HystrixShutdownHook hystrixShutdownHook() {
            return new HystrixShutdownHook();
        }
    
        @Bean
        public HasFeatures hystrixFeature() {
            return HasFeatures.namedFeatures(new NamedFeature("Hystrix", HystrixCommandAspect.class));
        }
        private class HystrixShutdownHook implements DisposableBean {
    
            @Override
            public void destroy() throws Exception {
                // Just call Hystrix to reset thread pool etc.
                Hystrix.reset();
            }
        }
    }
    

    从配置类中看到比较重要的就是AOP切面类的装配HystrixCommandAspect

    @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();
        }
        // 切点1
        @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")
        public void hystrixCommandAnnotationPointcut() {
        }
        // 切点2
        @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 {
                if (!metaHolder.isObservable()) {
                    result = CommandExecutor.execute(invokable, executionType, metaHolder);
                } else {
                    result = executeObservable(invokable, executionType, metaHolder);
                }
            } catch (HystrixBadRequestException e) {
                throw e.getCause();
            } catch (HystrixRuntimeException e) {
                throw hystrixRuntimeExceptionToThrowable(metaHolder, e);
            }
            return result;
        }
    }