嵌入式 Tomcat 作为嵌入 Java 应用程序的库, 你可以在 mvnrepository 下载 发行版Jar 以及源码

https://mvnrepository.com/search?q=embed+tomcat

作为最基本的依赖, 你需要以下几个库

  • Tomcat Embed Core
  • Tomcat Embed Logging JULI
  • Tomcat Annotations API

现在, 让我们把 tomcat 跑起来

package develon.test;import java.io.File;
import java.io.IOException;
import java.io.Writer;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;public final class Main {File tmpDir = new File("F:\\Game\\tomcat");Tomcat tomcat = new Tomcat();public static void main(String[] args) throws Throwable {new Main().init();}private void init() throws Throwable {Runtime.getRuntime().addShutdownHook(new Thread(() -> {try {tomcat.destroy();} catch (LifecycleException e) {e.printStackTrace();}}));test();}private void test() throws Throwable {tomcat.setBaseDir(tmpDir.getAbsolutePath()); // 设置工作目录tomcat.setHostname("localhost"); // 主机名, 将生成目录: {工作目录}/work/Tomcat/{主机名}/ROOTSystem.out.println("工作目录: " + tomcat.getServer().getCatalinaBase().getAbsolutePath());tomcat.setPort(80);Connector conn = tomcat.getConnector(); // Tomcat 9.0 必须调用 Tomcat#getConnector() 方法之后才会监听端口System.out.println("连接器设置完成: " + conn);// contextPath要使用的上下文映射,""表示根上下文// docBase上下文的基础目录,用于静态文件。相对于服务器主目录必须存在 ({主目录}/webapps/{docBase})Context ctx = tomcat.addContext("", /*{webapps}/~*/ "/ROOT");Tomcat.addServlet(ctx, "globalServlet", new HttpServlet() {private static final long serialVersionUID = 1L;@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setCharacterEncoding("UTF-8");response.setContentType("text/plain");response.setHeader("Server", "Embedded Tomcat");try (Writer writer = response.getWriter()) {writer.write("Hello, Embedded Tomcat!");writer.flush();}}});ctx.addServletMappingDecoded("/", "globalServlet");tomcat.start();System.out.println("tomcat 已启动");tomcat.getServer().await();}}

tomcat 嵌入正常, 让我们继续, 如何令 tomcat 加载 Spring Framework ?

嵌入式 tomcat 集成 Spring 框架

package develon.tomc;import java.util.HashSet;import org.apache.catalina.Context;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.startup.Tomcat;
import org.springframework.web.SpringServletContainerInitializer;public class Main {Tomcat tomcat;{tomcat = new Tomcat();
//      tomcat.setAddDefaultWebXmlToWebapp(false);
//      tomcat.noDefaultWebXmlPath();}public void run() throws Throwable {tomcat.setBaseDir("F:\\Game\\tomcat");tomcat.setHostname("localhost");tomcat.setPort(80);
//      tomcat.enableNaming();//      tomcat.getHost().setAutoDeploy(false);
//      tomcat.getEngine().setBackgroundProcessorDelay(-1);Context ctx = tomcat.addContext("", "ROOT");ctx.addLifecycleListener(new LifecycleListener() {public void lifecycleEvent(LifecycleEvent event) {
//              System.out.println(event.getLifecycle().getState().name());if (event.getLifecycle().getState() == LifecycleState.STARTING_PREP) {try {new SpringServletContainerInitializer().onStartup(new HashSet<Class<?>>() {private static final long serialVersionUID = 1L;{add(WebAppInitializer.class);}}, ctx.getServletContext());} catch (Throwable e) {e.printStackTrace();}}}});//      tomcat.init();tomcat.getConnector();tomcat.start();tomcat.getServer().await();}public static void main(String[] args) throws Throwable {new Main().run();}
}

其中 WebAppInitializer 是继承 AbstractAnnotationConfigDispatcherServletInitializer 的一个配置类
由于 AbstractAnnotationConfigDispatcherServletInitializer 继承了 SpringServletContainerInitializer, 所以可以简写为

        Context ctx = tomcat.addContext("", "ROOT");ctx.addLifecycleListener(new LifecycleListener() {public void lifecycleEvent(LifecycleEvent event) {if (event.getLifecycle().getState() == LifecycleState.STARTING_PREP) {try {new WebAppInitializer().onStartup(ctx.getServletContext());} catch (Throwable e) {e.printStackTrace();}}}});

这种方式好像会报一个错误, 不过可以忽略它, 但是注意这是一个运行时异常, 我们最好捕获 Throwable, 否则程序直接退出了
(经查, 是由于注射 dispacherServlet 两次造成的, 实际上第一次已经注射完成了)

java.lang.IllegalStateException: Failed to register servlet with name 'dispatcher'. Check if there is another servlet registered under the same name.at org.springframework.web.servlet.support.AbstractDispatcherServletInitializer.registerDispatcherServlet(AbstractDispatcherServletInitializer.java:90)at org.springframework.web.servlet.support.AbstractDispatcherServletInitializer.onStartup(AbstractDispatcherServletInitializer.java:63)at develon.tomc.Main$1.lifecycleEvent(Main.java:37)

然后我们还能用闭包进一步简化程序, 并且把烦人的栈痕迹删除

        ctx.addLifecycleListener((LifecycleEvent event) -> {if (event.getLifecycle().getState() == LifecycleState.STARTING_PREP) {try {new WebAppInitializer().onStartup(ctx.getServletContext());} catch (Throwable e) {
//                  e.printStackTrace();}}});

我用 kotlin 简单地封装了一个 EmbeddedTomcat 类

import org.apache.catalina.startup.Tomcat
import org.apache.catalina.Context
import org.apache.catalina.LifecycleStateclass EmbeddedTomcat {var tomcat: Tomcat = Tomcat()var ctx: Context? = nullinit {}/** 初始化嵌入式 tomcat */fun init() {tomcat.setBaseDir("""F:\\Game\\tomcat""")tomcat.setHostname("localhost")tomcat.setPort(80)ctx = tomcat.addContext("", "ROOT")}/** 开始监听服务 */fun run() {tomcat.getConnector()tomcat.start()tomcat.getServer().await()}/** 启动 Spring 框架, 注射 DispatcherServlet */fun spring() {var tyusya = falsectx?.addLifecycleListener {if (tyusya == false && it.getLifecycle().getState() == LifecycleState.STARTING_PREP) {println("开始注射 -> ${ it.getLifecycle().getState() }")val sctx = ctx?.getServletContext()try {WebAppInitializer().onStartup(sctx)println("完成")tyusya = true} catch(e: Throwable) {println("失败: ${ e.message }")}}}}fun spring2() { // 调用了 removeLifecycleListener 移除 tomcat 生命周期监听器ctx?.addLifecycleListener(object : LifecycleListener {override fun lifecycleEvent(it: LifecycleEvent) {if (it.getLifecycle().getState() == LifecycleState.STARTING_PREP) {println("开始注射 DispatcherServlet -> ${ it.getLifecycle().getState() }")try {WebAppInitializer().onStartup(ctx?.getServletContext())println("注射完成")ctx?.removeLifecycleListener(this)} catch(e: Throwable) {println("注射失败: ${ e.message }")}}}})}
}fun main() {val tomcat = EmbeddedTomcat()tomcat.init()tomcat.spring()tomcat.run()
}
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer
import org.springframework.context.annotation.ComponentScan@ComponentScan(basePackageClasses = [DefController::class])
class WebAppInitializer : AbstractAnnotationConfigDispatcherServletInitializer() {override fun getRootConfigClasses() = nulloverride fun getServletMappings() = arrayOf("/")override fun getServletConfigClasses() = arrayOf(WebAppInitializer::class.java)
}

转载于:https://www.cnblogs.com/develon/p/11602969.html

嵌入式 Tomcat (Embedded Tomcat)相关推荐

  1. 关于解决搭建Eureka出现的Unable to start embedded Tomcat;无法启动嵌入式tomcat异常

    今天在搭建Eureka的时候,死活都跑不起来!一直提示 Unable to start web server; nested exception is org.springframework.boot ...

  2. SpringBoot 嵌入式Tomcat无法启动:Unable to start embedded Tomcat

    问题: Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomc ...

  3. Nacos在双击startup.cmd启动时提示:Unable to start embedded Tomcat

    场景 Nacos简介.下载与配置持久化到Mysql: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/109356152 在下载Na ...

  4. Nacos 启动报错 Unable to start embedded Tomcat

    问题描述:Nacos官网下载下来的Nacos服务端(nacos-server-2.0.2.zip)在本地(Windows)环境下进行解压后,进入到其bin目录下面,双击"startup.cm ...

  5. Mac系统下运行Java项目出现Unable to start embedded Tomcat server解决方法

    克隆下来代码,运行项目出现如下报错 一直搜索Unable to start embedded Tomcat server这个报错,没有找到方法 下面这个提示也需要看:Caused by: java.n ...

  6. WebServerException: Unable to start embedded Tomcat

    先粘贴一下全部报错信息 [ERROR][2022-07-15 14:49:53 671][main][org.springframework.boot.SpringApplication] : App ...

  7. Springboot embedded Tomcat

    ​Springboot内置Tomcat启动过程 最近工作中需要在Tomcat端口启动后立即获取随机的端口号,所以研究了下Springboot相关的源码,在此记录下. 1. maven dependen ...

  8. Tomcat 之 tomcat安装和组件介绍

    1  概述 tomcat使用java语言编写,本身自带webser,是一个简装的http server,安装后生产的文件一般放在webapp下对应目录,manager是应用程序管理,tomcat 的站 ...

  9. Tomcat(1)介绍、jdk安装、安装Tomcat ​ 配置Tomcat监听80端口

    Tomcat介绍 (使用yum 下载安装的openjdk下载以后就可以使用) 以下实验用的是在官网下载程序包. Tomcat是一个中间键,要解析java相关的东西,需要先下载JDK 下载jdk 1.下 ...

  10. MyEclipse配置Tomcat没有Tomcat选项没有小猫图

    MyEclipse配置tomcat没有tomcat选项没有小猫图 本人使用MyEclipse10配置Tomcat服务器时,根据百度经验http://jingyan.baidu.com/article/ ...

最新文章

  1. null in JavaScript
  2. address标签,为网页加入地址信息
  3. 基于 Kyma 的企业级云原生应用的扩展案例分享
  4. kafka streams_Kafka REST Proxy MapR Streams入门
  5. C++ Makefile文件详解
  6. JAVA通过JCO连接SAP例子
  7. 合法C标识符(信息学奥赛一本通-T1134)
  8. 面试题:React实现鼠标托转文字绕原点旋转
  9. 软考常考知识点整理-项目风险管理计划
  10. NETAPP存储常用巡检命令
  11. 前后端分离 获取客户端ip_前后端分离交互
  12. 批量修改指定文件夹里面相同类型文件的扩展名(转自Github,原作者Crag Richards)
  13. kibana 失效原因 ,亲测有效
  14. 服务器光盘装centos7系统,光盘安装CentOS 7.4步骤
  15. 天鹅是白天的月亮(转)
  16. Pycharm、Idea登录GitHub报错,无法连接
  17. 为ibus安装极点五笔字库
  18. Python 设置随机 User-Agent (利用 fake_useragent包)
  19. NLP自然语言处理相关技术说明及样例(附源码)
  20. Linux 操作系统原理 — 进程管理 — 进程调度

热门文章

  1. 自学如何去学习jQuery
  2. maven远程私服发布jar包
  3. Android技术精髓-Bitmap详解
  4. 32 GroupSock(AddressPortLookupTable)——live555源码阅读(四)网络
  5. sql server从数据库导出导入教程
  6. Affinity Designer 查询面板渐变颜色
  7. 教你轻松搞定Vue事件总线(EventBus)
  8. SQL Server中数据库文件的存放方式,文件和文件组
  9. Boost Asio 使用技巧
  10. VS2015 优化选项的开启