我的主要目的是在没有任何web.xml
且没有Spring Boot的情况下,将Redhat's Undertow嵌入我的应用程序。 Undertow看起来距离servlet容器足够近,可以满足我的要求,同时性能卓越且精益。就其他微框架而言,我也研究了SparkJava,但由于其文档看起来更好,因此我首先尝试了Undertow。
因此,Undertow听起来不错,但是在/
返回“ Hello World ”后,遇到的所有文档和教程都停止了。也许我能找到的最好的是StubbornJava/RestServer.java,其中所有端点都是硬编码的,例如:
public static final RoutingHandler ROUTES = new RoutingHandler()
.get("/users", timed("listUsers", UserRoutes::listUsers))
我找不到什么显示了如何或是否有可能将Spring MVC / REST控制器注释与基本的Undertow结构链接起来。
我已经有一个带有在Spring注释中定义的一组端点的应用程序。
我对Spring和Undertow的知识缺少很多有关如何结合两者的知识,但是从Baeldung / Configuring Spring Boot可以看出,Spring提供了一种在Boot中使用Undertow的方法。我只是不需要Spring Boot。而且我真的不热衷于挖掘into the Spring source来了解Pivotal的工作方式,因为在我的情况下它可能无法复制。这是在Boot中实现它的方法:
@Bean
public UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory() {
UndertowEmbeddedServletContainerFactory factory =
new UndertowEmbeddedServletContainerFactory();
factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
@Override
public void customize(io.undertow.Undertow.Builder builder) {
builder.addHttpListener(8080, "0.0.0.0");
}
});
return factory;
}
我的猜测是,我必须以编程方式获取带注释的Spring REST控制器,并为每个控制器创建所需的Undertow资源。
似乎Undertow邮件列表也是不可搜索的。
答案 0 :(得分:1)
我不得不咬牙切齿,遍历Spring源代码,以了解Pivotal如何将所有内容捆绑在一起。
取出相关部分后,我将所得到的内容进行了重构,并将其归结为基本要素。第一个是集成测试类。
afterEach(function() {
console.log = originalLogFunction; // undo dummy log function
if (this.currentTest.state === 'failed') {
console.log(output);
}
});
然后我在实用程序类中进行了Undertow管道工程。我将其与Spring完全分开,这就是为什么我将 private static Undertow server;
@BeforeAll
public static void startServer() throws ServletException {
server = ServletUtils.buildUndertowServer(
8080,
"localhost",
"",
SpringServletContainerInitializer.class,
Collections.singleton(
MySpringServletInitializer.class),
MyTests.class.getClassLoader());
server.start();
}
@AfterAll
public static void stopServer() {
try {
if (server != null) {
server.stop();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testIsAvailable() {
Response response = get("/mystuff/isAvailable");
response.then().statusCode(200);
ResponseBody body = response.getBody();
assertThat("Body", body.asString(), is(equalTo("ok")));
}
的Spring实现作为参数发送的原因。
javax.servlet.ServletContainerInitializer
您必须实现Spring的import io.undertow.servlet.api.ServletContainerInitializerInfo;
import javax.servlet.ServletContainerInitializer;
public static Undertow buildUndertowServer(
int port,
String address,
String contextPath,
Class<? extends ServletContainerInitializer>
servletContainerInitializerClass,
Set<Class<?>> initializers,
ClassLoader classLoader
) throws ServletException {
ServletContainerInitializerInfo servletContainerInitializerInfo =
new ServletContainerInitializerInfo(
servletContainerInitializerClass,
initializers);
DeploymentInfo deployment = Servlets.deployment();
deployment.addServletContainerInitializer(
servletContainerInitializerInfo);
deployment.setClassLoader(classLoader);
deployment.setContextPath(contextPath);
deployment.setDisplayName("adam");
deployment.setDeploymentName("int-test");
deployment.setServletStackTraces(ServletStackTraces.ALL);
DeploymentManager manager =
Servlets.newContainer().addDeployment(deployment);
manager.deploy();
Undertow.Builder builder = Undertow.builder();
builder.addHttpListener(port, address);
HttpHandler httpHandler = manager.start();
httpHandler = Handlers.path().addPrefixPath(contextPath, httpHandler);
builder.setHandler(httpHandler);
return builder.build();
}
,并将其传递给Undertow,以便在servlet容器启动阶段由AbstractAnnotationConfigDispatcherServletInitializer
调用。
ServletContainerInitializer
此Spring servlet初始化程序将通过您的import javax.servlet.ServletContext;
import javax.servlet.ServletException;
public class MySpringServletInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {
MySpringWebApplicationContext.class
};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
public void onStartup(ServletContext servletContext)
throws ServletException {
logger.info("starting up");
super.onStartup(servletContext);
}
}
的实现(在那里的AnnotationConfigWebApplicationContext
方法中)调用Spring上下文初始化:
getRootConfigClasses
以这种方式在Undertow中启动整个Spring REST服务器大约需要1秒钟。 有了RESTassured进行测试,一切就变了。
答案 1 :(得分:0)
我创建了一个使用Spring和Undertow构建的示例项目。它还与JSP和Open Api 3.0集成在一起。您可以在这里查看:https://github.com/essentialprogramming/undertow-spring-web