Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application fails to start due to missing AbstractDiscoveryClientOptionalArgs bean #4185

Open
HJK181 opened this issue Jul 28, 2023 · 19 comments · May be fixed by #4259
Open

Application fails to start due to missing AbstractDiscoveryClientOptionalArgs bean #4185

HJK181 opened this issue Jul 28, 2023 · 19 comments · May be fixed by #4259

Comments

@HJK181
Copy link

HJK181 commented Jul 28, 2023

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
Copy link
Author

HJK181 commented Jul 28, 2023

Please also consider #4177 as my comments there were ignored.

@dnlnfr
Copy link

dnlnfr commented Jul 28, 2023

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.

@c4mpos
Copy link

c4mpos commented Jul 28, 2023

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

@abhayc77
Copy link

Same problem here.. any solution

@Shapoval1van
Copy link

Same problem

@Shapoval1van
Copy link

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

@HJK181
Copy link
Author

HJK181 commented Aug 3, 2023

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

@Shapoval1van
Copy link

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

@HJK181
Copy link
Author

HJK181 commented Aug 4, 2023

@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
Copy link
Author

HJK181 commented Sep 4, 2023

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?

@andytael
Copy link

andytael commented Sep 4, 2023 via email

@spencergibb
Copy link
Member

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.

@spring-cloud-issues
Copy link

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.

@HJK181
Copy link
Author

HJK181 commented Nov 18, 2023

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.

@andytael
Copy link

Spring 3.2.1 and Spring Cloud 2023.0.0 still have the same problem

@ZIRAKrezovic
Copy link
Contributor

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

Related: #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

@weiro-9-w7
Copy link

any update, the issue fixed ?

@zhangjunapk
Copy link

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

@rvervaek
Copy link

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();
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.