No qualifying bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>' available

本文将介绍怎样解决“No qualifying bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>' available: expected at least 1 bean which qualifies as autowire candidate.”错误。

不说什么开场白了,直接看详细的错误堆栈信息:

2021-03-09 13:19:01.333  WARN 10452 --- [  restartedMain] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration': Unsatisfied dependency expressed through field 'optionalArgs'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
2021-03-09 13:19:01.355  INFO 10452 --- [  restartedMain] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-03-09 13:19:01.407 ERROR 10452 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Field optionalArgs in org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration required a bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs' in your configuration.


Process finished with exit code 0

上面错误的大概意思为:在内部类 org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration

中 optionalArgs 字段依赖注入失败:

@Autowired
private AbstractDiscoveryClientOptionalArgs<?> optionalArgs;

为什么会注入失败呢?进入到 AbstractDiscoveryClientOptionalArgs 抽象类,他提供了如下子类实现:

No qualifying bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>' available

点击进入 RestTemplateDiscoveryClientOptionalArgs 子类,看看那些地方在使用它。在 DiscoveryClientOptionalArgsConfiguration 类中的 restTemplateDiscoveryClientOptionalArgs() 方法,它用来创建 RestTemplateDiscoveryClientOptionalArgs 对象,代码如下:

@Bean
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
@ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter")
@ConditionalOnMissingBean(value = { AbstractDiscoveryClientOptionalArgs.class }, search = SearchStrategy.CURRENT)
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", matchIfMissing = true,
      havingValue = "false")
public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs(TlsProperties tlsProperties,
      EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier)
      throws GeneralSecurityException, IOException {
   logger.info("Eureka HTTP Client uses RestTemplate.");
   RestTemplateDiscoveryClientOptionalArgs result = new RestTemplateDiscoveryClientOptionalArgs(
         eurekaClientHttpRequestFactorySupplier);
   setupTLS(result, tlsProperties);
   return result;
}

创建 RestTemplateDiscoveryClientOptionalArgs 对象是有条件,其中一个条件是类路径中必须有类才能创建它(因为有 @ConditionalOnClass 注解修饰)。而 RestTemplate 位于 spring-web-5.3.4.jar 文件。而 spring-web 位于中,如下图:

No qualifying bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>' available

因此,我们需要引入 spring-boot-start-web 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

问题解决了!

有读者会问,你怎么知道需要创建 RestTemplateDiscoveryClientOptionalArgs 类的对象,而不是其他子类呢?

(1)看看 DiscoveryClientOptionalArgs 类,根本没有被 new,如下图:

No qualifying bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>' available

(2)看看 Jersey1DiscoveryClientOptionalArgs 类,没有地方在使用,如下图:

No qualifying bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>' available

(3)看看 MutableDiscoveryClientOptionalArgs 类,创建代码如下:

@Bean
@ConditionalOnClass(name = "com.sun.jersey.api.client.filter.ClientFilter")
@ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT)
public MutableDiscoveryClientOptionalArgs discoveryClientOptionalArgs(TlsProperties tlsProperties)
      throws GeneralSecurityException, IOException {
   logger.info("Eureka HTTP Client uses Jersey");
   MutableDiscoveryClientOptionalArgs result = new MutableDiscoveryClientOptionalArgs();
   setupTLS(result, tlsProperties);
   return result;
}

他需要依赖 com.sun.jersey.api.client.filter.ClientFilter,过过……

(4)看看 WebClientDiscoveryClientOptionalArgs 类,下面是创建 WebClientDiscoveryClientOptionalArgs 的代码:

@ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter")
@ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient")
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", havingValue = "true")
protected static class WebClientConfiguration {

   @Autowired
   private TlsProperties tlsProperties;

   @Bean
   @ConditionalOnMissingBean(
         value = { AbstractDiscoveryClientOptionalArgs.class, RestTemplateDiscoveryClientOptionalArgs.class },
         search = SearchStrategy.CURRENT)
   public WebClientDiscoveryClientOptionalArgs webClientDiscoveryClientOptionalArgs(
         ObjectProvider<WebClient.Builder> builder) throws GeneralSecurityException, IOException {
      logger.info("Eureka HTTP Client uses WebClient.");
      WebClientDiscoveryClientOptionalArgs result = new WebClientDiscoveryClientOptionalArgs(
            builder::getIfAvailable);
      setupTLS(result, tlsProperties);
      return result;
   }

}

在 @ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", havingValue = "true") 中定义了,它需要依赖 webclient.enabled 属性。并且在 webClientDiscoveryClientOptionalArgs() 方法上还有 @ConditionalOnMissingBean 进行限制。

是不是感觉解决问题的思路清晰了那么一点点呢!!!

下图是问题解决后打断点查看 optionalArgs 字段的真实类型:

No qualifying bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>' available

谢谢支持……希望能帮助到你!

锲而舍之,朽木不折;锲而不舍,金石可镂。——《荀子·劝学》
0 不喜欢
说说我的看法 -
全部评论(

看到你写的这篇文章,非常详细,感谢你

回复:

谢谢支持!

关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号