天天看點

Hystrix核⼼源碼剖析

springboot裝配、⾯向切⾯程式設計、RxJava響應式程式設計的知識等等,我們剖析下主體脈絡。

分析⼊⼝:@EnableCircuitBreaker注解激活了熔斷功能,那麼該注解就是Hystrix源碼追蹤的⼊⼝.

@EnableCircuitBreaker注解激活熔斷器

EnableCircuitBreakerImportSelector 導入了一個 selector

/**
 * Annotation to enable a CircuitBreaker implementation.
 * http://martinfowler.com/bliki/CircuitBreaker.html
 * @author Spencer Gibb
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableCircuitBreakerImportSelector.class)
public @interface EnableCircuitBreaker {

}

           

檢視EnableCircuitBreakerImportSelector類

Hystrix核⼼源碼剖析

繼續關注⽗類 SpringFactoryImportSelector

annotationClass 擷取到的子類傳遞到父類的泛型,就是EnableCircuitbreaker的注解類

protected SpringFactoryImportSelector() {
		this.annotationClass = (Class<T>) GenericTypeResolver
				.resolveTypeArgument(this.getClass(), SpringFactoryImportSelector.class);
	}
           

selectImports方法中最終目的是要根據傳進來的泛型全限定類名作為key值 去spring.factories檔案查找對應的配置類 ,然後注入

@Override
	public String[] selectImports(AnnotationMetadata metadata) {
		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
		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
			log.warn("More than one implementation " + "of @" + getSimpleName()
					+ " (now relying on @Conditionals to pick one): " + factories);
		}

		return factories.toArray(new String[factories.size()]);
	}
           

spring.factories⽂件内容如下

Hystrix核⼼源碼剖析

關注切⾯:com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect

@Aspect
public class HystrixCommandAspect {

    private static final Map<HystrixPointcutType, MetaHolderFactory> META_HOLDER_FACTORY_MAP;


//切入定義點  關注添加了@HystrixCommand注解的方法
    @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 = 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;
    }

           

重點分析環繞通知⽅法

Hystrix核⼼源碼剖析

GenericCommand中根據中繼資料資訊重寫了兩個很核⼼的⽅法,⼀個是run⽅法封裝了對原始⽬标⽅法的調⽤,另外⼀個是getFallBack⽅法

它封裝了對回退⽅法的調⽤

另外,在GenericCommand的上層類構造函數中會完成資源的初始化,⽐如線程池

GenericCommand —>AbstractHystrixCommand—>HystrixCommand—>AbstractCommand
           
Hystrix核⼼源碼剖析
Hystrix核⼼源碼剖析
Hystrix核⼼源碼剖析
Hystrix核⼼源碼剖析
Hystrix核⼼源碼剖析
Hystrix核⼼源碼剖析
Hystrix核⼼源碼剖析

另外,我們觀察,GenericCommand⽅法中根據中繼資料資訊等重寫了run⽅法(對⽬标⽅法的調⽤),getFallback⽅法(對回退⽅法的調⽤),在RxJava處理過程中會完成對這兩個⽅法的調⽤。

Hystrix核⼼源碼剖析