前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在应用中嵌入Tomcat

在应用中嵌入Tomcat

作者头像
哲洛不闹
发布2018-09-18 11:22:33
2.3K0
发布2018-09-18 11:22:33
举报
文章被收录于专栏:java一日一条

很多 Java web 应用和服务,包括开源的和商业化的(比如 Alfresco, iRise, Confluence等),都倾向于将 Apache Tomcat Servlet 引擎整个嵌入到他们的分发包中。Atlatisan公司甚至只支持他们自己提供的嵌入式Tomcat 包,不再提供 WAR/EAR 形式的分发包。这些安装包包含了整个 Tomcat 引擎和配置文件,看起来确实有点大材小用。在大多数配置中,默认的配置文件甚至从来不会变动。真的有办法可以在代码中启动 Tomcat 并且只需要 tomcat 的 jar 文件作为依赖么?在下面的教程中,我们将会对 Jetty (Jetty 是一个为此目的而设计的一种嵌入式 servlet 引擎)进行测试,同时还会展示如何将 Jetty 迁移到 Tomcat 。

我开始研究嵌入式 Tomcat 是因为 BigSense 项目,该项目是一个开源 web 服务,用于模拟传感器网络。我的目的是可以将其作为一个标准的 Linux 软件包进行分发,这样就可以作为一个服务启动,而不用依赖于 Tomcat 软件包。下面的例子使用的是 Scala 语言,BigSense 项目用的也是这种开发语言,但是你也可以轻松地将所有源码和概念转换为 Java 语言。

首先,创建一个 trait(类似于 Java 中的接口),里面包含两个简单的功能,用于启动和停止 web 服务器。端口号可以从配置文件中获取。这是我的实现中唯一可配置的了,但是你也可以对 context path 添加配置。

下面是我使用 Scala 对 Jetty 的实现。大部分是直接从 Jetty 的官方文档中摘出来的。所有的静态资源(图片,CSS 和 javascript 脚本)都被直接打包到了 jar 文件中,可以作为类路径的资源进行访问。如果使用构建工具,如 SBT,Gradel 或者 Maven,可以将这些文件放到项目的 src/main/resources 目录下。Jetty 的 WebAppContext 允许调用 setResourceBase 来使用项目的静态资源。这个例子还展示了如何使用给定的 Context 路径来添加一个 Servlet (在这个例子中,只有一个 servlet,匹配根目录,名字为 MasterServlet)。还可以看到一个 EventListener 的例子。web.xml 中的大部分标准配置在 Jetty 中都可以使用代码进行设置。

Tomcat 的实现比较复杂。也没有足够的关于使用嵌入式 Tomcat 和配置代码的文档。在下面的例子中,我创建了一个 org.apache.catalina.startup.Tomcat 实例。当向 Tomcat 中添加 Servlets 时,因为一些原因需要指定它的工作目录。我这里是以一种平台依赖的方式使用系统属性 java.io.tmpdir 来获取一个临时文件夹。(注意:在本地环境下运行的时候会产生一个空的 ./tomcat.8080 目录)。虽然我不清楚怎样添加一个事件监听器,但却意识到了监听器甚至不会使用它持有的 context,因此只是手动调用它而没有使用context。最后,我在 Tomcat 的文档中没有找到类似 Jetty 中的 setResourceBase 方法来获取静态资源,因此只能创建一个自己的 StaticContentServlet,接下来将会看到。

这个获取静态资源的 servlet 只有一些基本功能。只是简单地找到类路径下的资源并返回。难点是正确地设置 Mime-Type。我尝试使用 javax.activation.FileTypeMap 基于扩展名来获取准确得 mime 类型,但是经常会得到错误的结果。因此,对于项目中已知静态文件的 mime 类型通过硬编码进行了实现。

依赖相当简单,只需添加需要的 Tomcat 和 Jetty 包就可以了。下面展示了在一个 buiuld.sbt 文件中的依赖,但这样的配置只能用于 Maven,Gradel或者Ivy。检查一下,然后确认你使用的是最近版本的 Jetty 以及/或者 Tomcat,因为它们可能会有变化。

从这里开始,创建一个 main 函数,然后启动你的服务器将会变得非常简单。我使用了一个名为 sbt-native-packager 的插件来创建 deb 和 rpm 文件,其中会用到相关的初始化脚本或 SystemD 服务文件。这么做允许你像安装一个标准的 Linux 安装包一样来安装 BigSense,作为标准服务独立于系统的 Tomcat,并且不需要多余的 war 或 ear 文件。

当然,这样做也有缺点。比如你有很多 web 应用都按这种方式进行部署,对于每个应用来讲就是启动一个完整 Tomcat 和 JVM 实例。即使 Tomcat 相对来讲(和 JBoss 或者 WebSphere 比起来)是轻量级的,仍然是比较重的,会耗费相当多的资源,这一点在虚拟机上尤为明显。

如果在你的空间中有很多 apps,使用系统中的 Tomcat 软件包,然后使用诸如 Fabric 之类的部署系统来维护、更新和部署你的 web 应用可能会更好点。如果你需要将应用打包给第三方,则使用嵌入式 Tomcat 是一个更好的解决方案。然而,当发现安全漏洞时,对于更新安装包来讲你就要小心了。对于嵌入式方法来讲,添加一个类似SSL的东西是比较复杂的,更好的解决方案是将类似 HAProxy 或者 Nginx 的软件作为前端代理来处理用户的 SSL 请求。

如果你是从零开始开发一个应用,应该考虑一下避免完全使用 Servlet 模式。在 JVM上,有很多为 web 服务和应用设计的异步框架,比如 Spray 和 Netty,远超这个设计于 1995 年的 HTTP Servlet API 。

如果你由于软件分发打算学习如何将 Tomcat 嵌入到 web 应用中,希望这篇教程可以帮到你。请时刻牢记以下这点,对于你给出的 jar 包和平台版本的 API 的变化,这些例子可能需要做一些调整来适配这些变化。虽然我只是讲到了 Tomcat 和 Jetty , 其实还有其它的嵌入式 Servlet 引擎,可以用相似的方式实现,甚至对于更新的非 Servlet 引擎(比如 Spray 和 Netty)来讲都有对 Servlet 的包装,这样你就可以在一些比较老的 web 应用上使用它们了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java一日一条 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档