为啥spring webflux默认选择jetty然后失败?

Posted

技术标签:

【中文标题】为啥spring webflux默认选择jetty然后失败?【英文标题】:Why spring webflux is choosing jetty by default and then failing?为什么spring webflux默认选择jetty然后失败? 【发布时间】:2018-05-24 13:38:50 【问题描述】:

我正在尝试运行基于 Spring boot 2.0.0.M7 的应用程序。

这是我在 build.gradle 中与 spring 相关的依赖项:

compile "org.springframework.boot:spring-boot-starter-webflux:2.0.0.M7"
compile "org.springframework.boot:spring-boot-starter-data-ldap:2.0.0.M7"
compile "org.springframework.boot:spring-boot-starter-actuator:2.0.0.M7"

根据自动配置报告,是否有可能告诉为什么 spring 默认要使用 Jetty 作为响应式引擎(实际上,根据 spring 文档,reactor Netty 是默认引擎)

spring boot 自动配置报告(摘录):

ReactiveWebServerConfiguration.ReactorNettyAutoConfiguration:
  Did not match:
     - @ConditionalOnMissingBean (types: org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; SearchStrategy: all) found beans of type'org.springframework.boot.web.reactive.server.ReactiveWebServerFactory'jettyReactiveWebServerFactory (OnBeanCondition)
  Matched:
     - @ConditionalOnClass found required class 'reactor.ipc.netty.http.server.HttpServer'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

ReactiveWebServerAutoConfiguration#defaultReactiveWebServerCustomizer matched:
      - @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.web.reactive.DefaultReactiveWebServerCustomizer; SearchStrategy: all) did not find any beans (OnBeanCondition)

   ReactiveWebServerConfiguration.JettyAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.eclipse.jetty.server.Server'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
      - @ConditionalOnMissingBean (types: org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; SearchStrategy: all) did not find any beans (OnBeanCondition)

我在应用程序启动期间遇到的异常:

[0;39morg.springframework.context.ApplicationContextException: Unable to start reactive web server; nested exception is java.lang.NoClassDefFoundError: org/eclipse/jetty/servlet/ServletHolder
    at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.onRefresh(ReactiveWebServerApplicationContext.java:64)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
    at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:49)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:327)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1245)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1233)
    at com.xyz.abc.routing.web.ApiApplication.main(ApiApplication.java:14)
    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.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.NoClassDefFoundError: org/eclipse/jetty/servlet/ServletHolder
    at org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory.createJettyServer(JettyReactiveWebServerFactory.java:96)
    at org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory.getWebServer(JettyReactiveWebServerFactory.java:87)
    at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.createWebServer(ReactiveWebServerApplicationContext.java:87)
    at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.onRefresh(ReactiveWebServerApplicationContext.java:61)
    ... 16 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.servlet.ServletHolder
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:93)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 20 common frames omitted

如何让 Spring 使用 reactor netty?

【问题讨论】:

如果您查看报告是使用Netty 匹配的规则。您的依赖项列表中有一些东西正在添加 Jetty。运行 gradle dependencies 以查看 Jetty 中的内容。 【参考方案1】:

正如 Marten 所提到的,检查您的依赖项以获取 Jetty Server 依赖项。 Spring Boot 正在寻找 org.eclipse.jetty.server.Server 类作为您选择 Jetty 作为服务器的信号。

试试./gradlew dependencies,看看这个依赖来自哪里。

【讨论】:

如果一个依赖需要 Jetty 来运行自己的功能,没有办法告诉 spring 仍然使用 netty?

以上是关于为啥spring webflux默认选择jetty然后失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Spring Webflux 只能并行接受 256 个请求?

为啥使用 webflux 进行 spring boot 测试会忽略自定义 jackson 模块

为啥 Spring WebFlux 应用程序不支持 @RestController 映射前缀?

在后台使用 Netty 与 Tomcat 时 Spring webFlux 的差异

更改 Webflux 在 Jetty 而不是 Netty 上运行后出现异常

覆盖 Spring webflux 项目的默认 Threadpool 执行器的效果如何?