Loading

SpringBoot在@PostConstruct方法中调用FeignClient加载不到Hystrix配置问题

版本信息

  • spring-cloud-starter-openfeign:2.1.3.RELEASE
  • spring-boot-starter-parent:2.2.2.RELEASE

问题描述

  • @Service@Autowired了一个@FeignClient,在@PostConstruct方法中调用此@FeignClient的方法,会直接进入Fallback,怀疑配置的Hystrix超时timeoutInMilliseconds配置没有生效

配置&代码

  • application. yml

    hystrix:
      threadpool:
        default:
          coreSize: 30
          maximumSize: 100
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 9000
    feign:
      hystrix:
        enabled: true
      httpclient:
        enabled: true
      client:
        config:
          default:
            connectTimeout: 3000
            readTimeout: 5000
    
  • @FeignClient

    @FeignClient(name = "dictionaryService", path = "internal/metrics", url = "${host}", decode404 = true, configuration = {ResponseDecoder.class}, fallback = DictionaryServiceFallback.class)
    public interface DictionaryService {
    
        @PostMapping("dictionary/getValueByPathKey")
        String getValueByPathKey(@RequestParam("path") String path, @RequestParam("key") String key);
    }
    
  • @Service

    @Slf4j
    @Service
    public class RsaServiceImpl implements RsaEncService {
    
        @Autowired
        private DictionaryService dictionaryService;
    
        private static String PUBLIC_KEY = null;
    
        private static String PRIVATE_KEY = null;
    
        private static final String XAPI_TOKEN = "xapi.token";
    
        @PostConstruct
        public void initKey() {
            PUBLIC_KEY = getPublicKey();
            PRIVATE_KEY = getPrivateKey();
        }
    
        @Override
        public String getPublicKey() {
            String value = dictionaryService.getValueByPathKey(XAPI_TOKEN, "public_key");
            if (StringUtils.isBlank(value)) {
                log.error("PublicKey获取失败");
            }
            return value;
        }
    
        @Override
        public String getPrivateKey() {
            String value = dictionaryService.getValueByPathKey(XAPI_TOKEN, "private_key");
            if (StringUtils.isBlank(value)) {
                log.error("PrivateKey获取失败");
            }
            return value;
        }
    
  • FallBack

    @Slf4j
    @Component
    public class DictionaryServiceFallback implements DictionaryService {
    
        @Override
        public String getValueByPathKey(String path, String key) {
            log.error("获取字典失败 , path : {}, key : {}", path, key);
            return null;
        }
    }
    

原因分析

  • 怀疑是在@Service的Bean创建后,@PostConstruct方法调用时,还没有加载Hystrix的配置,所以Hystrix使用的默认配置(默认timeoutInMilliseconds为1s)
  • debugHystrixCommandProperties,发现没有加载到Hystrix的配置。而实际Hystrix配置应该通过ArchaiusAutoConfiguration中的Bean:ConfigurableEnvironmentConfiguration负责加载
  • @FeignClient是通过@EnableFeignClients注解扫描组装Bean得到的,HystrixCommand是在使用@FeignClient时才创建,通过feign.hystrix.HystrixInvocationHandler#invoke方法
  • 在com.netflix.config.DynamicProperty#DynamicProperty(java.lang.String)构造函数中从ConcurrentCompositeConfiguration对象获取配置

解决

  • 使用@DependsOn("configurableEnvironmentConfiguration")注解

    • 单独控制可以加在@Service注解上

      @DependsOn("configurableEnvironmentConfiguration")
      @Slf4j
      @Service
      public class RsaServiceImpl implements RsaEncService {
          ......
      }
      
    • 全局控制加在Application启动类上

      @DependsOn("configurableEnvironmentConfiguration")
      @SpringBootApplication
      public class DevApplication{
          ......
      }
      

总结

  • HystrixCommand是在首次调用@FeignClient才初始化,所以需要确定Hystrix的配置此时是否已经加载到
  • Hystrix的配置默认是通过ArchaiusAutoConfiguration中的Bean--ConfigurableEnvironmentConfiguration负责加载
  • 确保在使用@FeignClientConfigurableEnvironmentConfiguration已经被加载

参考

posted @ 2022-08-30 17:40  FynnWang  阅读(1088)  评论(0编辑  收藏  举报