spring-cloud-netflix icon indicating copy to clipboard operation
spring-cloud-netflix copied to clipboard

Application fails to start due to missing AbstractDiscoveryClientOptionalArgs bean

Open HJK181 opened this issue 1 year ago • 22 comments

After updating Spring-Cloud from 2022.0.2 to 2022.0.3, our application failed to start:

***************************
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.

Our application is a mix of spring-boot web application and our internal core that relies on Grizzly and therefore ships org.glassfish.jersey.client.JerseyClient as a dependency. Besides the fact that this is a regression, I'm wondering what's the proper way to configure the eureka client if a JerseyClient is on the classpath?

As a workaround I created the following configuration class

@Profile("dev")
@Configuration
public class DiscoveryClientOptionalArgConfiguration {

	@Bean
	@ConditionalOnClass(name = { "org.springframework.web.client.RestTemplate", "org.glassfish.jersey.client.JerseyClient" })
	@ConditionalOnMissingBean(value = { AbstractDiscoveryClientOptionalArgs.class }, search = SearchStrategy.CURRENT)
	public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs(EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
		return new RestTemplateDiscoveryClientOptionalArgs(eurekaClientHttpRequestFactorySupplier);
	}

	@Bean
	@ConditionalOnClass(name = { "org.springframework.web.client.RestTemplate", "org.glassfish.jersey.client.JerseyClient" })
	@ConditionalOnMissingBean(value = { TransportClientFactories.class }, search = SearchStrategy.CURRENT)
	public RestTemplateTransportClientFactories restTemplateTransportClientFactories(RestTemplateDiscoveryClientOptionalArgs optionalArgs) {
		return new RestTemplateTransportClientFactories(optionalArgs);
	}
}

However, this should work out of the box with auto-configuration as it did before.

HJK181 avatar Jul 28 '23 06:07 HJK181

Please also consider https://github.com/spring-cloud/spring-cloud-netflix/issues/4177 as my comments there were ignored.

HJK181 avatar Jul 28 '23 06:07 HJK181

Same problem with SpringBoot 3.1.1 and SpringCloud 2022.0.3

***************************
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.

However i tried this eureka client cloned from here: repository The service registers correctly and works. The versions are the same.

dnlnfr avatar Jul 28 '23 09:07 dnlnfr

Same problem here, also with Spring boot 3.1.1 and Spring Cloud 2022.0.3

c4mpos avatar Jul 28 '23 17:07 c4mpos

Same problem here.. any solution

abhayc77 avatar Jul 30 '23 05:07 abhayc77

Same problem

Shapoval1van avatar Aug 03 '23 11:08 Shapoval1van

@HJK181 are you sure that is ok to change @ConditionalOnMissingClass to @ConditionalOnClass

Shapoval1van avatar Aug 03 '23 13:08 Shapoval1van

@Shapoval1van For our purpose as both classes are on the classpath it's enough. However, we only use Eureka for local development ... I doubt that this is a reasonable general-purpose fix ...

HJK181 avatar Aug 03 '23 13:08 HJK181

@HJK181 I see that exist some Jersey3DiscoveryClientOptionalArgs here but I can not find a source.

Shapoval1van avatar Aug 03 '23 20:08 Shapoval1van

@Shapoval1van The auto-configuration happens inside the spring-cloud-netflix-eureka-client: https://github.com/spring-cloud/spring-cloud-netflix/blob/v4.0.3/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientOptionalArgsConfiguration.java#L67

There you can see that the default RestTemplateDiscoveryClientOptionalArgs is not configured when you have org.glassfish.jersey.client.JerseyClient on the classpath. My workaround above configures the default behavior even though JerseyClient is on the classpath, as I didn't want a discovery client based on Jersey but on RestTemplate. However, if you want a Jersey discovery client, there is Jersey3DiscoveryClientOptionalArgs which is shipped as part of com.netflix.eureka:eureka-client-jersey3 dependency. However, that dependency is only shipped as part of spring-cloud-starter-netflix-server and not when you actually need it in spring-cloud-starter-netflix-eureka-client

image

HJK181 avatar Aug 04 '23 05:08 HJK181

I have nothing more than what I’ve posted in the issue description. What is the exact error you get?

My workaround only works if you have JerseyClient and RestTemplate on your classpath. Are you sure the letter is on the classpath as well?

HJK181 avatar Sep 04 '23 16:09 HJK181

My bad,I did a rookie mistake. ThanksOn Sep 4, 2023, at 11:44 AM, HJK181 @.***> wrote: I have nothing more than what I’ve posted in the issue description. What is the exact error you get? My workaround only works if you have JerseyClient and RestTemplate on your classpath. Are you sure the letter is on the classpath as well?

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: @.***>

andytael avatar Sep 04 '23 18:09 andytael

We long have assumed that if you have jersey on the classpath then that is what you want to use for eureka since that is the default from Netflix and spring cloud changed our default to RestTemplate.

Maybe adding some documentation to https://docs.spring.io/spring-cloud-netflix/docs/current/reference/html/#eurekaclient-with-jersey

Not sure what else to do.

spencergibb avatar Nov 10 '23 17:11 spencergibb

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

spring-cloud-issues avatar Nov 17 '23 17:11 spring-cloud-issues

I don’t know what more feedback I could provide. Everything is described in the ticket, even a necessary workaround. For me the better solution on a clash of the two classes would be to have a property that when set, ignores Jersey on the classpath for every auto configuration checking it class presents.

HJK181 avatar Nov 18 '23 09:11 HJK181

Spring 3.2.1 and Spring Cloud 2023.0.0 still have the same problem

andytael avatar Feb 19 '24 16:02 andytael

Adding my findings from another bug that I created, missing this one

Related: https://github.com/spring-cloud/spring-cloud-netflix/issues/4177

When jeresey-client lib is present on the class path, in my case via spring-boot-starter-jeresey, application startup will fail with

Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'eurekaAutoServiceRegistration'
...
Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.cloud.netflix.eureka.CloudEurekaClient.getApplications()" because the return value of "org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration.getEurekaClient()" is null
        at org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry.maybeInitializeClient(EurekaServiceRegistry.java:54) ~[spring-cloud-netflix-eureka-client-4.1.0.jar:4.1.0]
        at org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry.register(EurekaServiceRegistry.java:38) ~[spring-cloud-netflix-eureka-client-4.1.0.jar:4.1.0]

Auto configuration report for DiscoveryClientOptionalArgsConfiguration

   DiscoveryClientOptionalArgsConfiguration#defaultEurekaClientHttpRequestFactorySupplier matched:
      - @ConditionalOnClass found required class 'org.springframework.web.client.RestTemplate' (OnClassCondition)
      - @ConditionalOnMissingBean (types: org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier; SearchStrategy: all) did not find any beans (OnBeanCondition)

   DiscoveryClientOptionalArgsConfiguration#restTemplateDiscoveryClientOptionalArgs:
      Did not match:
         - @ConditionalOnMissingClass found unwanted class 'org.glassfish.jersey.client.JerseyClient' (OnClassCondition)

   DiscoveryClientOptionalArgsConfiguration#restTemplateTransportClientFactories:
      Did not match:
         - @ConditionalOnMissingClass found unwanted class 'org.glassfish.jersey.client.JerseyClient' (OnClassCondition)

   DiscoveryClientOptionalArgsConfiguration.DiscoveryClientOptionalArgsTlsConfiguration:
      Did not match:
         - @ConditionalOnBean (types: com.netflix.discovery.AbstractDiscoveryClientOptionalArgs; SearchStrategy: current) did not find any beans of type com.netflix.discovery.AbstractDiscoveryClientOptionalArgs (OnBeanCondition)
      Matched:
         - @ConditionalOnClass found required class 'org.glassfish.jersey.client.JerseyClient' (OnClassCondition)

   DiscoveryClientOptionalArgsConfiguration.WebClientConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'org.springframework.web.reactive.function.client.WebClient' (OnClassCondition)

   DiscoveryClientOptionalArgsConfiguration.WebClientNotFoundConfiguration:
      Did not match:
         - @ConditionalOnMissingClass found unwanted class 'org.glassfish.jersey.client.JerseyClient' (OnClassCondition)

Further analysis

To use JereseyClient with eureka, the eureka-client-jeresey3 library must be present on the class path. Suggestion: change conditionals from org.glassfish.jersey.client.JerseyClient to, for example, com.netflix.discovery.shared.transport.jersey3.EurekaJersey3Client

Eureka Server, which depends on the eureka-client-jeresey3 publishes two beans

import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs;
import com.netflix.discovery.Jersey3DiscoveryClientOptionalArgs;
import com.netflix.discovery.shared.transport.jersey.TransportClientFactories;
import com.netflix.discovery.shared.transport.jersey3.Jersey3TransportClientFactories;

@Bean
@ConditionalOnMissingBean(AbstractDiscoveryClientOptionalArgs.class)
public Jersey3DiscoveryClientOptionalArgs jersey3DiscoveryClientOptionalArgs() {
    return new Jersey3DiscoveryClientOptionalArgs();
}

@Bean
@ConditionalOnMissingBean(TransportClientFactories.class)
public Jersey3TransportClientFactories jersey3TransportClientFactories() {
    return Jersey3TransportClientFactories.getInstance();
}

So even if eureka-client-jeresey3 and jeresey-client are present, application will still fail to start unless those two beans are also published.

Sample

https://github.com/ZIRAKrezovic/eureka-reproducer

./mvnw clean package spring-boot:run

ZIRAKrezovic avatar Feb 19 '24 19:02 ZIRAKrezovic

any update, the issue fixed ?

weiro-9-w7 avatar Mar 18 '24 06:03 weiro-9-w7

Same problem Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.cloud.netflix.eureka.CloudEurekaClient.getApplications()" because the return value of "org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration.getEurekaClient()" is null at org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry.maybeInitializeClient(EurekaServiceRegistry.java:83) ~[spring-cloud-netflix-eureka-client-4.1.1.jar:4.1.1] at org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry.register(EurekaServiceRegistry.java:66) ~[spring-cloud-netflix-eureka-client-4.1.1.jar:4.1.1] at org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration.start(EurekaAutoServiceRegistration.java:89) ~[spring-cloud-netflix-eureka-client-4.1.1.jar:4.1.1] at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:288) ~[spring-context-6.1.6.jar:6.1.6] ... 13 common frames omitted

zhangjunapk avatar May 09 '24 13:05 zhangjunapk

I'm having the same issue.

As I understand, the issue seems to be a lack of a com.netflix.discovery.shared.transport.jersey.TransportClientFactories bean and com.netflix.discovery.Jersey3DiscoveryClientOptionalArgs bean, when org.glassfish.jersey.client.JerseyClient is on the classpath. Can the solution simply be to declare these in org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration?

Something along these lines:

    @ConditionalOnClass(name = "org.glassfish.jersey.client.JerseyClient")
    protected static class Jersey3ClientConfiguration {

        @Bean
        @ConditionalOnMissingBean(value = { AbstractDiscoveryClientOptionalArgs.class }, search = SearchStrategy.CURRENT)
        public Jersey3DiscoveryClientOptionalArgs jersey3DiscoveryClientOptionalArgs() {
            return new Jersey3DiscoveryClientOptionalArgs();
        }
        
        @Bean
        @ConditionalOnMissingBean(value = TransportClientFactories.class, search = SearchStrategy.CURRENT)
        public Jersey3TransportClientFactories jersey3TransportClientFactories() {
            return Jersey3TransportClientFactories.getInstance();
        }
    }

rvervaek avatar May 23 '24 10:05 rvervaek

same error with spring boot 3.3.1 and spring cloud 2023.0.2

works with workaround proposed by @HJK181

samuelfac avatar Jun 21 '24 16:06 samuelfac

@spencergibb I'm thinking we could add an opt-in flag (true by default) that the users could use to disable using JerseyClient even if it's on the classpath. wdyt?

OlgaMaciaszek avatar Jun 26 '24 14:06 OlgaMaciaszek

Yeah, that's fine

spencergibb avatar Jun 26 '24 14:06 spencergibb