其實只是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,注意SpringFactoryImportSelector類的泛型類型為EnableCircuitBreaker:
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableCircuitBreakerImportSelector extends SpringFactoryImportSelector<EnableCircuitBreaker> {@Overrideprotected 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方法:
@Overridepublic 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文件下的EnableCircuitBreakerList<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 factorythis.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 {@Beanpublic HystrixCommandAspect hystrixCommandAspect() {return new HystrixCommandAspect();}@Beanpublic 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背景知識做支撐。
有空再聊:) ~!