Bootstrap

如何将 Tomcat 服务器嵌入 Java Web 应用程序

Tomcat 是一个非常流行的 Web 服务器,用于托管 Java Web 应用程序。与将 Java Web 应用程序部署在独立 Tomcat 实例上的典型开发场景相比,您可以将服务器运行时直接集成到应用程序中,从而获得一些有趣且方便的 Tomcat 使用方式。

在本文中,我们将与您分享一些将 Tomcat 服务器嵌入 Java 应用程序的方法。

表中的内容:

1. 为什么使用嵌入式 Tomcat?嵌入式 Tomcat 的 Maven 依赖项

2.嵌入式Tomcat的Maven依赖

. Tomcat 嵌入 API

. 为程序化 Java Web 应用程序嵌入 Tomcat 服务器

. 将嵌入式 Tomcat 服务器用于 WAR 文件

. 为现有 Java Web 应用程序嵌入 Tomcat 服务器

 

1. 为什么使用嵌入式 Tomcat?嵌入式 Tomcat 的 Maven 依赖项

基本上,我们希望将嵌入式 Tomcat 用于以下目的:

- 对 Java servlet 等 Web 组件进行快速单元测试:无需启动/停止 Tomcat 服务器并打开 Web 浏览器进行手动单元测试,而是可以使用嵌入式 Tomcat 来自动化单元测试。

- 将 Java Web 应用程序作为独立的 Java 应用程序交付:最终用户现在可以运行 JAR 文件,该文件启动托管 Web 应用程序的嵌入式服务器。无需手动下载和安装 Tomcat 和部署 Web 应用程序。

- 服务器的编程控制:集成嵌入式服务器允许您以编程方式对服务器进行更多控制,并自动执行手动步骤。

- 你能想象到的。

 

2.嵌入式Tomcat的Maven依赖

为了使用嵌入式 Tomcat 并将其运行时打包到您的 Java Web 应用程序中,请在 Maven 的 pom.xml 文件中添加以下依赖项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-core</artifactId>
    <version>${tomcat.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <version>${tomcat.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-logging-juli</artifactId>
    <version>${tomcat.version}</version>
</dependency>

其中 tomcat.version 是指向 Tomcat 实际版本的属性:

1
2
3
<properties>
    <tomcat.version>8.0.48</tomcat.version>
</properties>

如果您不使用 Maven,请 下载 以下 JAR 文件并将其添加到项目的类路径中:

  • ecj-3.12.3.jar
  • tomcat-annotations-api-8.0.48.jar
  • tomcat-embed-core-8.0.48.jar
  • tomcat-embed-el-8.0.48.jar
  • tomcat-embed-jasper-8.0.48.jar
  • tomcat-embed-logging-juli-8.0.48.jar

 

请注意,版本号可能与此处显示的不同。

 

3. Tomcat 嵌入 API

中心类是org.apache.catalina.startup.Tomcat,它可以让您控制嵌入式服务器的几乎所有内容:创建新实例、配置服务器、添加 Web 应用程序、添加 servlet、启动和停止服务器等。

例如,以下代码创建并启动在端口号 8080 上运行的嵌入式 Tomcat 实例:

1
2
3
4
5
6
7
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
 
// configure the server
// configure web applications
 
tomcat.start();

您可以使用以下方法来配置服务器:

  • setBaseDir(String baseDir):设置服务器工作的基本目录。这应该是第一个调用的方法。默认情况下,Tomcat 尝试按以下顺序使用这些系统属性:catalina.basecatalina.homeuser.dir
  • setHostname(String name):设置默认主机的主机名。默认为“本地主机”。
  • setPort(int port):设置默认连接器的端口号。

 

要以编程方式创建 Web 应用程序,请使用以下方法向服务器添加上下文:

                addContext(字符串 contextPath,字符串 docBase)

其中contextPath是 Web 应用程序名称,docBase是应用程序的基本目录。此方法返回一个表示单个 Web 应用程序的Context对象。您可以使用此Context对象来配置 Web 应用程序的各个方面,例如:

1
2
3
4
5
6
7
// add context initialization parameters
context.addParameter("param1""value1");
context.addParameter("param2""value2");
 
context.addErrorPage(new ErrorPage());
context.setCookies(true);
context.setSessionTimeout(30);

要为现有的 Web 应用程序配置服务器,请使用以下Tomcat的方法:

                addWebapp(字符串 contextPath,字符串 baseDir)

其中contextPath是 Web 应用程序名称,baseDir是应用程序的基本目录。baseDir可以引用外部 WAR 文件,或同一项目中的 Web 应用程序目录。

要将现有的 Java servlet 添加到 Web 应用程序,可以使用以下方法:

addServlet(String contextPath, String servletName, Servlet servlet)

或者使用下面的静态方法:

Tomcat.addServlet(上下文上下文,字符串 servletName,Servlet servlet)

要为 servlet 配置 URL 映射,可以使用Context类的以下方法:

addServletMappingDecoded(String urlPattern, String servletName)

启动、停止和销毁服务器:

      tomcat.start()

      tomcat.stop()

      tomcat.destroy()

要使当前线程等待服务器关闭,请使用以下语句:

1
tomcat.getServer().await();

如需完整参考,请阅读TomcatContext类的 Javadocs 。

 

4. 为程序化 Java Web 应用程序嵌入 Tomcat 服务器

在这种方法中,您可以从头开始以编程方式创建一个完整的 Java Web 应用程序。没有现有的 Web 应用程序,也没有现有的 servlet。

例如,下面的程序SimpleWebApp创建了一个嵌入式 Tomcat 的实例,一个位于根上下文路径(“/”)下的 Web 应用程序,一个名为“Servlet1”的 Java servlet,并将这个 servlet 映射到 URL 模式“/go”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package net.codejava;
 
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
 
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.startup.Tomcat;
 
public class SimpleWebApp {
 
    public static void main(String[] args) throws LifecycleException {
        Tomcat tomcat = new Tomcat();
        tomcat.setBaseDir("temp");
        tomcat.setPort(8080);
         
        String contextPath = "/";
        String docBase = new File(".").getAbsolutePath();
         
        Context context = tomcat.addContext(contextPath, docBase);
         
        HttpServlet servlet = new HttpServlet() {
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                    throws ServletException, IOException {
                PrintWriter writer = resp.getWriter();
                 
                writer.println("<html><title>Welcome</title><body>");
                writer.println("<h1>Have a Great Day!</h1>");
                writer.println("</body></html>");
            }
        };
         
        String servletName = "Servlet1";
        String urlPattern = "/go";
         
        tomcat.addServlet(contextPath, servletName, servlet);      
        context.addServletMappingDecoded(urlPattern, servletName);
         
        tomcat.start();
        tomcat.getServer().await();
    }
}

如您所见,“动态”创建了一个 Java servlet,它覆盖了doGet()方法:

1
2
3
4
5
6
7
8
9
10
11
HttpServlet servlet = new HttpServlet() {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
 
        writer.println("<html><title>Welcome</title><body>");
        writer.println("<h1>Have a Great Day!</h1>");
        writer.println("</body></html>");
    }
};

这个 servlet 向客户端发送一个简单的 HTML 页面,标题为“祝你有美好的一天!”。

在 Eclipse 中运行这个程序,您可以在 Console 视图中看到服务器的日志:

服务器正在侦听端口 8080,因此在 Web 浏览器中键入以下 URL:

http://localhost:8080/去

你可以看到结果是这样的:

 

这意味着服务器和 Web 应用程序已启动并正在运行。

您还可以像这样在单独的类 ( AddServlet.java ) 中编写 Servlet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package net.codejava;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class AddServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        int a = Integer.parseInt(req.getParameter("a"));
        int b = Integer.parseInt(req.getParameter("b"));
        int sum = a + b;
         
        String result = String.format("%d + %d = %d", a, b, sum);
         
        PrintWriter writer = resp.getWriter();
        writer.println("<html><title>Addition</title><body>");
        writer.println("<h1>" + result + "</h1");
        writer.println("</body></html>");
    }
}

此 servlet 返回从查询参数传递的两个数字的总和。并将这个 servlet 添加到 Web 应用程序中,如下所示:

1
2
3
4
5
6
AddServlet addServlet = new AddServlet();
servletName = "AddServlet";
urlPattern = "/add";
 
tomcat.addServlet(contextPath, servletName, addServlet);
context.addServletMappingDecoded(urlPattern, servletName);

从 Web 浏览器调用 servlet:

http://localhost:8080/add?a=1234&b=5678

结果:

在这种编程模式下,没有 JSP 支持。这种方法适用于创建带有嵌入式 Tomcat 服务器的最小、简单、轻量级的 Web 应用程序。

要在 Eclipse IDE 中为此类应用程序创建可执行 JAR 文件,请单击File > Export...Export对话框中,选择Java > Runnable JAR file并单击Next。在Runnable JAR File Export屏幕中,记得选择“将所需库复制到生成的 JAR 旁边的子文件夹中”选项,如以下屏幕截图所示:

单击Finish,eclipse 会在生成的 JAR 旁边的目录中生成可执行 JAR 文件以及嵌入式 Tomcat 所需的 JAR 文件。然后您可以使用 java 命令运行应用程序,如下所示:

1
java -jar SimpleWebApp2.jar

然后您可以看到服务器已启动并准备好接受客户端的请求。

 

5. 将嵌入式 Tomcat 服务器用于 WAR 文件

嵌入式 Tomcat 的一个有趣特性是您可以以编程方式启动服务器以运行打包在 Web 存档 (WAR) 文件中的 Java Web 应用程序。

假设您在Bookstore.war文件中打包了一个 Java Web 应用程序,以下程序将创建一个 Tomcat 实例并从 WAR 文件中添加一个 Web 应用程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package net.codejava;
 
import javax.servlet.ServletException;
 
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
 
public class RunWarExample {
 
    public static void main(String[] args) throws ServletException, LifecycleException {
        Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("temp");
        tomcat.setPort(8080);
         
        String contextPath = "/Bookstore";     
        String warFilePath = "D:\\Web\\Website\\Bookstore.war";
         
        tomcat.getHost().setAppBase(".");
         
        tomcat.addWebapp(contextPath, warFilePath);
         
        tomcat.start();
        tomcat.getServer().await();
    }
}

运行此程序,您可以看到 WAR 文件的内容被提取到基本目录,您可以使用指定的上下文路径访问 Web 应用程序。

这种方法对于测试打包在 WAR 文件中的现有 Web 应用程序非常方便,并且您不必接触它们的代码。

对于此类应用程序,以与程序化 Web 应用程序中所述相同的方式生成可执行 JAR 文件。

 

6. 为现有的 Java Web 应用程序嵌入 Tomcat 服务器

这也许是嵌入式 Tomcat 最常用的特性。这是这样的场景:您正在开发一个 Java Web 应用程序,现在您想要嵌入 Tomcat 以进行单元测试或将 Web 应用程序作为独立的 Java 程序交付。那么如何制作呢?

假设您的 Web 应用程序的文件存储在名为WebContent的目录中,如下所示:

以下程序启动一个嵌入式 Tomcat 实例来运行 Web 应用程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package net.codejava.servlet;
 
import java.io.File;
 
import javax.servlet.ServletException;
 
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
 
public class EmbeddedTomcatTest {
 
    public static void main(String[] args) throws LifecycleException, ServletException {
        String contextPath = "/UploadApp";
        String webappDir = new File("WebContent").getAbsolutePath();
                 
        Tomcat tomcat = new Tomcat();
        tomcat.setBaseDir("temp");
        tomcat.setPort(8080);
         
        tomcat.addWebapp(contextPath, webappDir);
         
        tomcat.start();
        tomcat.getServer().await();    
    }
}

现在您可以使用浏览器使用上面程序中指定的端口号和上下文路径访问 Web 应用程序:

http://localhost:8080/UploadApp/upload.jsp

要为此类应用程序生成可执行 JAR 文件,您需要使用 Tomcat Maven 插件,如此所述。

 

API 参考:

类 Tomcat  Javadoc

类 上下文 Javadoc

;