第四十讲-Tomcat内嵌容器
第四十讲-Tomcat内嵌容器
这一讲,我们来学习一下Tomcat内嵌容器。我们首先看一下Tomcat容器的重要组成:
如上面的这张图,展示了Tomcat中一些重要的组件。
- Connector:连接器,连接器决定了将来请求是以什么协议,哪个端口来连接到Tomcat服务器上
- Engine:执行引擎,负责Tomcat运行
接下来我们通过编程的方式来创建内嵌的Tomcat
public class TestTomcat {
/*
Server
└───Service
├───Connector (协议, 端口)
└───Engine
└───Host(虚拟主机 localhost)
├───Context1 (应用1, 可以设置虚拟路径, / 即 url 起始路径; 项目磁盘路径, 即 docBase )
│ │ index.html
│ └───WEB-INF
│ │ web.xml (servlet, filter, listener) 3.0
│ ├───classes (servlet, controller, service ...)
│ ├───jsp
│ └───lib (第三方 jar 包)
└───Context2 (应用2)
│ index.html
└───WEB-INF
web.xml
*/
@SuppressWarnings("all")
public static void main(String[] args) throws LifecycleException, IOException {
// 1.创建 Tomcat 对象
Tomcat tomcat = new Tomcat();
// 设置一个基础目录
tomcat.setBaseDir("tomcat");
// 2.创建项目文件夹(此处是临时目录), 即 docBase 文件夹
File docBase = Files.createTempDirectory("boot.").toFile();
// 当程序退出时删除该临时目录
docBase.deleteOnExit();
// 3.创建 Tomcat 项目, 在 Tomcat 中称为 Context,默认路径为'/',这里只需要写空字符串即可
Context context = tomcat.addContext("", docBase.getAbsolutePath());
WebApplicationContext springContext = getApplicationContext();
// 4.编程添加 Servlet
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
HelloServlet helloServlet = new HelloServlet();
// 添加HelloServlet并为此田添加一个映射路径
ctx.addServlet("aaa", helloServlet).addMapping("/hello");
// DispatcherServlet dispatcherServlet = springContext.getBean(DispatcherServlet.class);
// ctx.addServlet("dispatcherServlet", dispatcherServlet).addMapping("/");
for (ServletRegistrationBean registrationBean : springContext.getBeansOfType(ServletRegistrationBean.class).values()) {
registrationBean.onStartup(ctx);
}
}
}, Collections.emptySet());
// 5.启动 Tomcat
tomcat.start();
// 6.创建连接器, 设置监听端口-->底层使用NIO的HTTP1.1协议
Connector connector = new Connector(new Http11Nio2Protocol());
// 设置Tomcat端口号
connector.setPort(8080);
// 将连接器设置到Tomcat中
tomcat.setConnector(connector);
}
}
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print("""
<h3>hello</h3>
""");
}
}
启动依赖测试一下:
接下来我们来看一下内嵌Tomcat与Spring是怎么结合在一起使用的?
首先编写一个Spring容器:
public static WebApplicationContext getApplicationContext() {
// AnnotationConfigServletWebServerApplicationContext
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
// 设置配置类
context.register(Config.class);
// 完成容器的初始化
context.refresh();
return context;
}
改造相关代码:
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
HelloServlet helloServlet = new HelloServlet();
// 添加HelloServlet并为此田添加一个映射路径
ctx.addServlet("aaa", helloServlet).addMapping("/hello");
// DispatcherServlet dispatcherServlet = springContext.getBean(DispatcherServlet.class);
// ctx.addServlet("dispatcherServlet", dispatcherServlet).addMapping("/");
for (ServletRegistrationBean registrationBean : springContext.getBeansOfType(ServletRegistrationBean.class).values()) {
registrationBean.onStartup(ctx);
}
}
}, Collections.emptySet());
配置类如下:
@Configuration
static class Config {
// DispatcherServlet Register Bean
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
// Dispatcher Servlet Bean
@Bean
// 这个例子中必须为 DispatcherServlet 提供 AnnotationConfigWebApplicationContext, 否则会选择 XmlWebApplicationContext 实现
public DispatcherServlet dispatcherServlet(WebApplicationContext applicationContext) {
return new DispatcherServlet(applicationContext);
}
// 处理器适配器,并添加一个JSON格式消息转换器
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter handlerAdapter = new RequestMappingHandlerAdapter();
handlerAdapter.setMessageConverters(List.of(new MappingJackson2HttpMessageConverter()));
return handlerAdapter;
}
// 一个简单的控制器
@RestController
static class MyController {
@GetMapping("hello2")
public Map<String,Object> hello() {
return Map.of("hello2", "hello2, spring!");
}
}
}
测试运行如下:
分类:
Spring 高级49讲
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构