快捷搜索:  汽车  科技

spring cloud 技术实现方法(SpringcloudFeign)

spring cloud 技术实现方法(SpringcloudFeign)LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(this.annotationClass this.beanClassLoader)));@Order(2147483547) public class EnableCircuitBreakerImportSelector extends SpringFactoryImportSelector<EnableCircuitBreaker> { public EnableCircuitBreakerImportSelector() { } protected Boolean isEnabled() { return (Boolean)this.getEnvironment().getProperty("spring.cloud



spring cloud 技术实现方法(SpringcloudFeign)(1)

hystrix 流程图


Netflix Hystrix已经停止更新目前处于维护状态,在SpringCloud中对服务的调用通常是用feign完成的,如果同时想使用hystrix做熔断则只需如下配置就可以完成(前提已经引入了feign相关依赖)

  • 引入springcloud hystrix starter 依赖
  • 在application.properties 里添加feignclient enable hystrix 配置
  • 在启动主类上增加 @EnableHystrix 注解
  • 在feign接口上配置好fallback类即可

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>

feign.hystrix.enbaled=true

@EnableHystrix @EnableFeignClients @EnableDiscoveryClient @SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class args); } }

@Component public class UserFallBack implements UserFeignClient{ @Override public String getUser() { return "fall back"; } } @FeignClient(value = "eureka-provider" fallback = UserFallBack.class) public interface UserFeignClient { @GetMapping("/user") String getUser(); }

通过以上配置就可以使用带有hystrix的FeignClient了,本文将重点放在Feign与Hystrix的集成上看看其原理是怎么样的分析思路按照如下顺序进行

  • EnableHystrix 工作原理
  • FeignAutoConfiguration 中 HystrixTargeter分析
  • FeignClientsConfiguration中Feign.Builder分析
  • FeignClientFactoryBean中loadBalance分析

EnableHystrix 分析

首先看下该注解定义发现该注解中开启了EnableCircuitBreaker(断路器注解)该注解才是将Hystrix相关beanDefinition扫描至spring容器的关键

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @EnableCircuitBreaker public @interface EnableHystrix { }

在EnableCircuitBreaker接口中出现了熟悉的Import注解,此注解中EnableCircuitBreakerImportSelector类将完成bean的扫描工作

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

接下来分析下EnableCircuitBreakerImportSelector工作原理,首先进入EnableCircuitBreakerImportSelector发现只有一个isEnable方法而且默认是开启状态,此时selectImports方法并没有Override父类中的方法直接查看父类中该方法

@Order(2147483547) public class EnableCircuitBreakerImportSelector extends SpringFactoryImportSelector<EnableCircuitBreaker> { public EnableCircuitBreakerImportSelector() { } protected Boolean isEnabled() { return (Boolean)this.getEnvironment().getProperty("spring.cloud.circuit.breaker.enabled" Boolean.class Boolean.TRUE); } }

由于enable默认为true,执行else中方法最为重要的方法为SpringFactoriesLoader.loadFactoryNames 如果看过springboot启动主类的源码话该方法的作用就是将jar包中META-INF/spring.factories解析并加入到容器中而HystrixCircuitBreakerConfiguration为hystrix核心配置类会初始化相关bean,可查阅相关类进行查看

LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(this.annotationClass this.beanClassLoader)));

public String[] selectImports(AnnotationMetadata metadata) { if (!this.isEnabled()) { return new String[0]; } else { AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.annotationClass.getName() true)); Assert.notNull(attributes "No " this.getSimpleName() " attributes found. Is " metadata.getClassName() " annotated with @" this.getSimpleName() "?"); List<String> factories = new ArrayList(new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(this.annotationClass this.beanClassLoader))); if (factories.isEmpty() && !this.hasDefaultFactory()) { throw new IllegalStateException("Annotation @" this.getSimpleName() " found but there are no implementations. Did you forget to include a starter?"); } else { if (factories.size() > 1) { this.log.warn("More than one implementation of @" this.getSimpleName() " (now relying on @Conditionals to pick one): " factories); } return (String[])factories.toArray(new String[factories.size()]); } } }

FeignAutoConfiguration

该类中生成了Targeter而Targeter的生成是根据classpath下是否存在 feign.hystrix.HystrixFeign内存则生成HystrixTargeter

@Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "feign.hystrix.HystrixFeign") protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new HystrixTargeter(); } } @Configuration(proxyBeanMethods = false) @ConditionalOnMissingClass("feign.hystrix.HystrixFeign") protected static class DefaultFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new DefaultTargeter(); } }

FeignClientsConfiguration

此类主要是根据applicaton.yml或application.properties是否存在如下配置

feign.hystrix.enabled = true

如果classpath同时 存在HystrixCommand.class HystrixFeign.class 则Feign.Builder 为HystrixFeign.builder()

@Configuration(proxyBeanMethods = false) @ConditionalOnClass({ HystrixCommand.class HystrixFeign.class }) protected static class HystrixFeignConfiguration { @Bean @Scope("prototype") @ConditionalOnMissingBean @ConditionalOnProperty(name = "feign.hystrix.enabled") public Feign.Builder feignHystrixBuilder() { return HystrixFeign.builder(); } }

至此Hystrix依赖基本加载完毕

FeignClientFactoryBean

最终在获取FeignClient对象的时候通过FeignClientFactoryBean类getObject方法 最终会调用getTarget方法,此方法中会寻找Feign.Builder 也就是Hystix builder至此FeignClient与Hystrix整合完成

<T> T getTarget() { FeignContext context = this.applicationContext.getBean(FeignContext.class); Feign.Builder builder = feign(context); if (!StringUtils.hasText(this.url)) { if (!this.name.startsWith("http")) { this.url = "http://" this.name; } else { this.url = this.name; } this.url = cleanPath(); return (T) loadBalance(builder context new HardCodedTarget<>(this.type this.name this.url)); } .........省略部分代码................. }

总结

其实整合流程并不复杂,在接下来的文章会继续分析Hystrix的工作原理,如果对整合流程的细节比较感兴趣可以通过debug方式进行单步调试分析

下一篇文章主要对Hystrix进行分析

猜您喜欢: