248 lines
9.9 KiB
Markdown
248 lines
9.9 KiB
Markdown
|
---
|
|||
|
title: springMvc整合undertow容器
|
|||
|
|
|||
|
categories: 毕业设计
|
|||
|
|
|||
|
date: 2023-02-09 10:39:24
|
|||
|
|
|||
|
tags:
|
|||
|
|
|||
|
- java
|
|||
|
|
|||
|
- spring mvc
|
|||
|
|
|||
|
- undertow
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
> 因为项目要求用springMvc,但是默认以war包发布到tomact下每一次启动都会很慢,所以希望能用一个嵌入式的web容器,了解到undertow对于小型项目还不错,就使用了undertow.
|
|||
|
|
|||
|
> 最开始用的Jfinal-undertow,但是突然看到出了spring6.0,就想体验一下,spring6.0对应的servlet版本比较高,jfinal-undertow并不兼容,所以就自己找到了undertow进行使用,以下就是折腾的经历。
|
|||
|
|
|||
|
# 1. 依赖安装
|
|||
|
|
|||
|
```xml
|
|||
|
<!-- https://mvnrepository.com/artifact/io.undertow/undertow-servlet -->
|
|||
|
<dependency>
|
|||
|
<groupId>io.undertow</groupId>
|
|||
|
<artifactId>undertow-servlet</artifactId>
|
|||
|
<version>2.3.3.Final</version>
|
|||
|
</dependency>
|
|||
|
|
|||
|
<!-- https://mvnrepository.com/artifact/io.undertow/undertow-core -->
|
|||
|
<dependency>
|
|||
|
<groupId>io.undertow</groupId>
|
|||
|
<artifactId>undertow-core</artifactId>
|
|||
|
<version>2.3.3.Final</version>
|
|||
|
</dependency>
|
|||
|
```
|
|||
|
|
|||
|
在项目原本的依赖下加入以上两个依赖,版本需要对应一样,分别是undertow的核心依赖和undertow的servlet相关实现。
|
|||
|
|
|||
|
# 2. 运行整合
|
|||
|
|
|||
|
## 2.1 添加servlet
|
|||
|
|
|||
|
```java
|
|||
|
// 创建servletInfo,指定servlet的命名和servlet对应的class
|
|||
|
ServletInfo info = new ServletInfo("mvc", DispatcherServlet.class)
|
|||
|
// 添加映射路径
|
|||
|
.addMapping("/")
|
|||
|
// 设置InitParam,制定了spring-mvc的配置文件位置
|
|||
|
.addInitParam("contextConfigLocation","classpath:spring-config/spring-mvc.xml")
|
|||
|
// 设置什么时候进行初始化
|
|||
|
.setLoadOnStartup(1);
|
|||
|
```
|
|||
|
|
|||
|
## 2.2 创建容器
|
|||
|
|
|||
|
undertow的一个web容器就是一个**DeploymentManager**,该接口的默认实现类就是**DeploymentManagerImpl**,然后需要两个参数,分别是**DeploymentInfo**和**ServletContainer**,所以需要先创建DeploymentInfo,然后创建ServletContainer,因为ServletContainer也需要DeploymentInfo作为参数,代码如下所示。
|
|||
|
|
|||
|
```java
|
|||
|
// 创建DeploymentInfo 对象
|
|||
|
DeploymentInfo deploymentInfo = new DeploymentInfo()
|
|||
|
// 指定类加载器
|
|||
|
.setClassLoader(TestServer.class.getClassLoader())
|
|||
|
// 设置contextPath
|
|||
|
.setContextPath("/")
|
|||
|
// 设置容器名称
|
|||
|
.setDeploymentName("myUndertow")
|
|||
|
// 设置初始化参数,制定了spring的配置文件的位置
|
|||
|
.addInitParameter("contextConfigLocation","classpath:spring-config/spring.xml")
|
|||
|
// 设置了一个监听器,用于初始化spring
|
|||
|
.addListener(new ListenerInfo(ContextLoaderListener.class))
|
|||
|
// 添加servlet
|
|||
|
.addServlet(info)
|
|||
|
// 添加一个过滤器,放置乱码问题
|
|||
|
.addFilter(
|
|||
|
new FilterInfo("Encoding", CharacterEncodingFilter.class)
|
|||
|
.addInitParam("encoding","utf-8")
|
|||
|
);
|
|||
|
// 创建一个ServletContainer,并添加deploymentInfo
|
|||
|
ServletContainerImpl container = new ServletContainerImpl();
|
|||
|
container.addDeployment(deploymentInfo);
|
|||
|
// 创建一个DeploymentManagerImpl
|
|||
|
DeploymentManagerImpl manager = new DeploymentManagerImpl(deploymentInfo, container);
|
|||
|
// 部署该容器,一定要部署否则会报各种空指针
|
|||
|
manager.deploy();
|
|||
|
```
|
|||
|
|
|||
|
## 2.3 添加HttpHandler
|
|||
|
|
|||
|
因为是web项目,所以使用HttpHandler,HttpHandler默认有很多实现类,这里使用了最好理解的**PathHandler**,创建完之后添加到**Undertow**的Builder参数中,作为一个Listener,然后启动Undertow。
|
|||
|
|
|||
|
```java
|
|||
|
// 创建一个PathHandler,然后添加一个前缀匹配,DeploymentManagerImpl 调用start方法后会返回一个HttpHandler类型
|
|||
|
PathHandler root = new PathHandler().addPrefixPath(deploymentInfo.getContextPath(), manager.start());
|
|||
|
// 创建一个Undertow对象并配置启动的端口等参数,然后调用start方法启动
|
|||
|
Undertow.Builder builder = Undertow.builder().addHttpListener(port, host, root);
|
|||
|
Undertow undertow = builder.build();
|
|||
|
undertow.start();
|
|||
|
logger.info(" the undertow success listen http://"+host+":"+port);
|
|||
|
```
|
|||
|
|
|||
|
## 2.4 读取配置文件
|
|||
|
|
|||
|
我也希望向springBoot项目一样可以直接读取端口等参数直接启动,但是因为容器运行时spring容器还没有运行,所以我才用的方法是手动读取文件并注入字段。
|
|||
|
|
|||
|
```java
|
|||
|
public void initConfig(String configPath) throws IllegalAccessException {
|
|||
|
if (configPath.equals("")){
|
|||
|
configPath = "config/application.yml";
|
|||
|
}
|
|||
|
// 读取yaml文件并转换为propperties
|
|||
|
YamlPropertiesFactoryBean propertiesFactoryBean = new YamlPropertiesFactoryBean();
|
|||
|
propertiesFactoryBean.setResources(new ClassPathResource(configPath));
|
|||
|
// 配置log4j基本信息
|
|||
|
PropertyConfigurator.configure(propertiesFactoryBean.getObject());
|
|||
|
// 读取当前类的字段
|
|||
|
Field[] fields = this.getClass().getDeclaredFields();
|
|||
|
for (Field field:fields
|
|||
|
) {
|
|||
|
// 检查是否包含Value注解
|
|||
|
if (field.getAnnotation(Value.class) != null) {
|
|||
|
String value = field.getAnnotation(Value.class).value();
|
|||
|
value = value.substring(2).substring(0, value.length() - 3);
|
|||
|
// 注入参数
|
|||
|
field.set(this,propertiesFactoryBean.getObject().get(value));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@Value("${server.host}")
|
|||
|
public String host;
|
|||
|
|
|||
|
@Value("${server.port}")
|
|||
|
public Integer port;
|
|||
|
```
|
|||
|
|
|||
|
# 3. 最后
|
|||
|
|
|||
|
完整代码如下
|
|||
|
|
|||
|
```java
|
|||
|
package org.gjs;
|
|||
|
|
|||
|
import io.undertow.Undertow;
|
|||
|
import io.undertow.server.handlers.PathHandler;
|
|||
|
import io.undertow.servlet.UndertowServletMessages;
|
|||
|
import io.undertow.servlet.api.DeploymentInfo;
|
|||
|
import io.undertow.servlet.api.FilterInfo;
|
|||
|
import io.undertow.servlet.api.ListenerInfo;
|
|||
|
import io.undertow.servlet.api.ServletInfo;
|
|||
|
import io.undertow.servlet.core.DeploymentImpl;
|
|||
|
import io.undertow.servlet.core.DeploymentManagerImpl;
|
|||
|
import io.undertow.servlet.core.ManagedServlet;
|
|||
|
import io.undertow.servlet.core.ServletContainerImpl;
|
|||
|
import io.undertow.servlet.handlers.ServletHandler;
|
|||
|
import io.undertow.servlet.handlers.ServletInitialHandler;
|
|||
|
import io.undertow.servlet.handlers.ServletPathMatches;
|
|||
|
import io.undertow.servlet.spec.ServletContextImpl;
|
|||
|
import jakarta.servlet.ServletException;
|
|||
|
import org.apache.log4j.Logger;
|
|||
|
import org.apache.log4j.PropertyConfigurator;
|
|||
|
import org.gjs.config.MyUndertowConfig;
|
|||
|
import org.springframework.beans.factory.annotation.Value;
|
|||
|
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
|||
|
import org.springframework.core.io.ClassPathResource;
|
|||
|
import org.springframework.http.server.reactive.UndertowHttpHandlerAdapter;
|
|||
|
import org.springframework.web.context.ContextLoaderListener;
|
|||
|
import org.springframework.web.filter.CharacterEncodingFilter;
|
|||
|
import org.springframework.web.servlet.DispatcherServlet;
|
|||
|
|
|||
|
import java.lang.reflect.Field;
|
|||
|
|
|||
|
public class TestServer {
|
|||
|
|
|||
|
private final Logger logger = Logger.getLogger(this.getClass());
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public static void main(String[] args) throws ServletException, IllegalAccessException {
|
|||
|
TestServer server = new TestServer();
|
|||
|
server.initConfig("");
|
|||
|
server.start();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public void initConfig(String configPath) throws IllegalAccessException {
|
|||
|
if (configPath.equals("")){
|
|||
|
configPath = "config/application.yml";
|
|||
|
}
|
|||
|
YamlPropertiesFactoryBean propertiesFactoryBean = new YamlPropertiesFactoryBean();
|
|||
|
propertiesFactoryBean.setResources(new ClassPathResource(configPath));
|
|||
|
// 配置log4j基本信息
|
|||
|
PropertyConfigurator.configure(propertiesFactoryBean.getObject());
|
|||
|
|
|||
|
Field[] fields = this.getClass().getDeclaredFields();
|
|||
|
for (Field field:fields
|
|||
|
) {
|
|||
|
if (field.getAnnotation(Value.class) != null) {
|
|||
|
String value = field.getAnnotation(Value.class).value();
|
|||
|
value = value.substring(2).substring(0, value.length() - 3);
|
|||
|
field.set(this,propertiesFactoryBean.getObject().get(value));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@Value("${server.host}")
|
|||
|
public String host;
|
|||
|
|
|||
|
@Value("${server.port}")
|
|||
|
public Integer port;
|
|||
|
|
|||
|
public void start() throws ServletException {
|
|||
|
|
|||
|
ServletInfo info = new ServletInfo("mvc", DispatcherServlet.class)
|
|||
|
.addMapping("/")
|
|||
|
.addInitParam("contextConfigLocation","classpath:spring-config/spring-mvc.xml")
|
|||
|
.setLoadOnStartup(1);
|
|||
|
|
|||
|
DeploymentInfo deploymentInfo = new DeploymentInfo()
|
|||
|
.setClassLoader(TestServer.class.getClassLoader())
|
|||
|
.setContextPath("/")
|
|||
|
.setDeploymentName("myUndertow")
|
|||
|
.addInitParameter("contextConfigLocation","classpath:spring-config/spring.xml")
|
|||
|
.addListener(new ListenerInfo(ContextLoaderListener.class))
|
|||
|
.addServlet(info)
|
|||
|
.addFilter(
|
|||
|
new FilterInfo("Encoding", CharacterEncodingFilter.class)
|
|||
|
.addInitParam("encoding","utf-8")
|
|||
|
);
|
|||
|
|
|||
|
ServletContainerImpl container = new ServletContainerImpl();
|
|||
|
container.addDeployment(deploymentInfo);
|
|||
|
DeploymentManagerImpl manager = new DeploymentManagerImpl(deploymentInfo, container);
|
|||
|
manager.deploy();
|
|||
|
|
|||
|
PathHandler root = new PathHandler().addPrefixPath(deploymentInfo.getContextPath(), manager.start());
|
|||
|
Undertow.Builder builder = Undertow.builder().addHttpListener(port, host, root);
|
|||
|
Undertow undertow = builder.build();
|
|||
|
undertow.start();
|
|||
|
logger.info(" the undertow success listen http://"+host+":"+port);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
```
|