不说什么开场白了,直接看详细的错误堆栈信息:
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 抽象类,他提供了如下子类实现:
点击进入 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 位于中,如下图:
因此,我们需要引入 spring-boot-start-web 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
问题解决了!
有读者会问,你怎么知道需要创建 RestTemplateDiscoveryClientOptionalArgs 类的对象,而不是其他子类呢?
(1)看看 DiscoveryClientOptionalArgs 类,根本没有被 new,如下图:
(2)看看 Jersey1DiscoveryClientOptionalArgs 类,没有地方在使用,如下图:
(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 字段的真实类型:
谢谢支持……希望能帮助到你!
看到你写的这篇文章,非常详细,感谢你
谢谢支持!