我们在spring-integration
中有一个项目,该项目将与webflex
或servlet
实现一起使用,这似乎在使用spring.main.web-application-type
属性集作为系统属性时工作得很好。
我现在正在寻找如何在运行时选择嵌入式 Web 服务器。
spring-boot
文档说,这是通过pom.xml
的依赖项包含或排除来实现的。
https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/howto-embedded-web-servers.html
我正在寻找的是能够从同一个项目/可执行 jar 启动任何jetty
、netty
、undertow
或tomcat
。
这在SpringApplication中的某些特定启动序列中可行吗?
感谢您的任何指示/建议。
您可以将所有这些作为test
范围的依赖项,并使用Spring Boot的FilteredClassLoader
来排除当前单元测试中不需要的任何内容:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.developing-auto-configuration.testing.overriding-classpath。
您可能需要了解 Web 服务器的所有这些自动配置的详细信息,以确定要排除的确切类。
对于当前测试中不需要的特定自动配置,也可以仅使用普通@SpringBootApplication.exclude()
(或类似的配置属性)来实现目标。
不过与弹簧集成无关。
我认为我已经找到了一种相对简单和干净的方法来做到这一点。
在创建应用程序上下文时,spring-boot
根据属性spring.main.web-application-type
中的值,以两种方式之一加载WebServerApplicationContext
:reactive
或servlet
(分别为ReactiveWebServerApplicationContext
和ServletWebServerApplicationContext
)。
这两个类都有一个方法createWebServer()
该方法将查找(分别)ReactiveWebServerFactory
或加载到上下文中的ServletWebServerFactory
类型的 bean,在这种情况下,该 bean 将是WebApplicationContext
使用的WebServerFactory
。
因此需要将目标WebServerFactory
声明为 bean。
有许多不同的方法可以执行此操作,包括使用配置文件。
我选择使用工厂 bean,它将WebServerFactory
实例化为系统属性的函数,这里my.main.web-server
(作为spring.main.web-application-type
的并行)。
使用BeanFactory
创建保存WebServerFactory
的 bean:
package net.demo;
...
public class MyWebServerFactoryBeanFactory implements EnvironmentAware {
private Environment environment;
public ReactiveWebServerFactory createReactiveWebServerFactory() {
switch(getWebServer()) {
case "jetty":
return new JettyReactiveWebServerFactory();
case "netty":
return new NettyReactiveWebServerFactory();
case "undertow":
return new UndertowReactiveWebServerFactory();
case "tomcat":
case default:
return new TomcatReactiveWebServerFactory();
}
}
public ServletWebServerFactory createServletWebServerFactory() {
switch(getWebServer()) {
case "jetty":
return new JettyServletWebServerFactory();
case "undertow":
return new UndertowServletWebServerFactory();
case "tomcat":
case default:
return new TomcatServletWebServerFactory();
}
}
private String getWebServer() {
return environment.getProperty("my.main.web-server");
}
}
使用 XML 上下文定义,我定义了 BeanFactory 并导入了一个对于reactive
和servlet
不同的源代码:
...
<import resource="classpath:my-${spring.main.web-application-type:servlet}.xml" />
<bean id="myWebServerFactoryBeanFactory"
class="net.demo.MyWebServerFactoryBeanFactory" />
...
最后,在特定源文件中创建WebServerFactory
。my-reactive.xml
内:
<bean id="myWebServerFactory" factory-bean="net.demo.MyWebServerFactoryBeanFactory"
factory-method="createReactiveWebServerFactory" />
并在my-servlet.xml
内:
<bean id="myWebServerFactory" factory-bean="net.demo.MyWebServerFactoryBeanFactory"
factory-method="createServletWebServerFactory" />
我想您不一定需要专门的导入,因为您可以在上下文中创建ReactiveWebServerFactory
和ServletWebServerFactory
,但只会使用匹配的 bean。