blog/java相关/springMvc整合undertow.md

248 lines
9.9 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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项目所以使用HttpHandlerHttpHandler默认有很多实现类这里使用了最好理解的**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);
}
}
```