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

Unable to use reactive WebClient without spring-boot-starter-reactor-netty #9690

Closed
michael-simons opened this issue Jul 6, 2017 · 13 comments
Assignees
Labels
type: documentation A documentation update
Milestone

Comments

@michael-simons
Copy link
Contributor

This is probably more of a documentation issue but when developing a reactive application on Tomcat (and probably others) and you exclude starter-reactor-netty like this

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-reactor-netty</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>            
</dependency>

then WebClient won't work. The class is on the path but creating a new one with return WebClient.create("http://localhost:8080"); will fail:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.reactive.function.client.WebClient]: Factory method 'webClient' threw exception; nested exception is java.lang.NoClassDefFoundError: reactor/ipc/netty/http/client/HttpClient
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:182)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:575)
	... 43 common frames omitted
Caused by: java.lang.NoClassDefFoundError: reactor/ipc/netty/http/client/HttpClient
	at org.springframework.http.client.reactive.ReactorClientHttpConnector.<init>(ReactorClientHttpConnector.java:47)
	at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.initExchangeFunction(DefaultWebClientBuilder.java:139)
	at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.build(DefaultWebClientBuilder.java:115)
	at org.springframework.web.reactive.function.client.WebClient.create(WebClient.java:173)
	at com.example.demo.NewClass$CustomConfig.webClient(NewClass.java:29)
	at com.example.demo.NewClass$CustomConfig$$EnhancerBySpringCGLIB$$7b5a2896.CGLIB$webClient$0(<generated>)
	at com.example.demo.NewClass$CustomConfig$$EnhancerBySpringCGLIB$$7b5a2896$$FastClassBySpringCGLIB$$783fa80e.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:359)
	at com.example.demo.NewClass$CustomConfig$$EnhancerBySpringCGLIB$$7b5a2896.webClient(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:155)
	... 44 common frames omitted
Caused by: java.lang.ClassNotFoundException: reactor.ipc.netty.http.client.HttpClient
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 6, 2017
@bclozel
Copy link
Member

bclozel commented Jul 6, 2017

Yes, indeed, reactor-netty is still required if you want to use the WebClient.

I'll turn this into a documentation improvement. Is there a particular piece of documentation that you find misleading? Or did you just apply the same reasoning that you'd use with spring-boot-starter-web?

@bclozel bclozel self-assigned this Jul 6, 2017
@bclozel bclozel added priority: high type: documentation A documentation update and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 6, 2017
@bclozel bclozel added this to the 2.0.0.M3 milestone Jul 6, 2017
@michael-simons
Copy link
Contributor Author

I expected only the runtime plattform to change. I understand what's happening and I'd know how to fix it, but it's annoying and should be part of the docs. Something like: "if you want to use tc or undertow do this, but take care of including Reactor-Netty if you need web client"

@bclozel bclozel closed this as completed in 7bbae21 Jul 7, 2017
@dancingfrog
Copy link

This is actually a bigger issue in that if we include the spring-boot-starter-reactor-netty or spring-webflux dependencies in order to use WebClient in our application, then the application itself (@SpringBootApplication) will always start an embedded web server listening on port 8080. There seems to be no exclusion that will prevent this behavior and still allow the application to use WebClient or other reactive web classes. The cause is pretty well documented here: https://www.changchao.me/?p=316

@wilkinsona
Copy link
Member

@dancingfrog You can set the web application type to none when creating your SpringApplication.

@dancingfrog
Copy link

@rameshsunkara

This comment has been minimized.

@philwebb

This comment has been minimized.

@rameshsunkara

This comment has been minimized.

@madhtr
Copy link

madhtr commented Jul 23, 2021

@dancingfrog You can set the web application type to none when creating your SpringApplication.

True. But if I am creating a project intended to be used as a maven dependency in another project, the developer on the dependent project will have to do this as well.

Excluding spring-boot-starter-tomcat worked with spring boot web. But it does not work with webflux. This is not ideal IMHO.

Respectfully.

@gfinger
Copy link

gfinger commented Feb 14, 2023

I use the WebClient in a library which is used in console applications. A web server is not needed and only increases the overall size of the jar. According to me requiring a web server when you only need the client contradicts the idea of autoconfiguration. If there is no server in the classpath everything depending on it should not be configured. This is the idea of the "@ConditionalOn..." annotations, no?

@bclozel
Copy link
Member

bclozel commented Feb 14, 2023

@gfinger since this issue got resolved, Spring Boot can now auto-configure WebClient using Reactor Netty, Apache HttpComponent, Jetty client and the JDK 11 java.net.http.HttpClient. If it's not working as expected, can you create a new issue with a sample application showing the problem?

@gfinger
Copy link

gfinger commented Feb 15, 2023

@bclozel this might be a misunderstanding. It is possible to configure the http-client, yes. But you can not have the http-client without the server. I get the error message:

Web application could not be started as there was no org.springframework.boot.web.reactive.server.ReactiveWebServerFactory bean defined in the context.

I know that I could use the whole webflux-starter dependency and disable the start of the server, for example in a console application. But this still gets me a lot of things in my jar, that are not needed. And, additionally, if I add the webflux-starter in a reuse-library, I have to advise all consumers of my library to take care about the required server. Not nice.

As said above: I would expect that If there is no http-server in the classpath, the autoconfiguration considers this correctly and does not try to configure any component that might need the server.

I open another issue about this topic.

@bendathierrycom
Copy link

@gfinger We cannot have everything with a small footprints. Maybe you can use other webclient impl available like okhttp or httpcomponents. I think you will then have a smaller stuff embedded inside your java application's classpath.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation A documentation update
Projects
None yet
Development

No branches or pull requests

10 participants