嵌入式 Web 服务器:Tomcat/Jetty/Undertow 的配置与优化

好的,没问题!咱们这就来聊聊嵌入式 Web 服务器那点事儿,保证让你看完之后,感觉自己也能在家里搭个“小网站”了!

嵌入式 Web 服务器:Tomcat/Jetty/Undertow 的配置与优化

各位看官,今天咱们不聊宇宙飞船,也不谈量子力学,就说说这嵌入式 Web 服务器。啥叫嵌入式?简单来说,就是把 Web 服务器“塞”到你的应用程序里,让你的程序也能像个网站一样提供服务。

想象一下,你写了个智能家居控制程序,想用手机远程控制家里的灯泡。如果你的程序内嵌了一个 Web 服务器,你就可以直接用手机浏览器访问,而不需要再额外安装一个庞大的 Web 服务器软件。是不是很酷?

说到嵌入式 Web 服务器,就不得不提 Tomcat、Jetty 和 Undertow 这三位“大佬”。它们都是 Java 世界里的明星,各有所长,各有千秋。今天,咱们就来扒一扒它们的配置和优化技巧,让你的嵌入式应用跑得更快更稳。

一、三位“大佬”的自我介绍

在深入了解配置和优化之前,咱们先来认识一下这三位“大佬”。

  • Tomcat:身经百战的老将

    Tomcat 绝对是 Web 服务器界的“老将”,它历史悠久,功能强大,是 Java Web 应用的首选。Tomcat 不仅仅是一个 Web 服务器,更是一个 Servlet 容器,它可以运行各种 Java Web 应用,比如 JSP、Servlet 等。

    优点:

    • 成熟稳定,经过了无数项目的考验。
    • 功能丰富,支持各种 Web 标准。
    • 社区庞大,遇到问题容易找到解决方案。

    缺点:

    • 相对笨重,启动速度较慢。
    • 资源占用较高,不太适合对资源要求苛刻的嵌入式环境。
    • 配置较为复杂,需要一定的学习成本。
  • Jetty:轻量级的灵活选手

    Jetty 就像一个“灵活的胖子”,它身材轻盈,启动速度快,非常适合嵌入式环境。Jetty 不仅仅可以作为 Web 服务器,还可以作为 HTTP 客户端使用,这让它在很多场景下都非常有用。

    优点:

    • 轻量级,启动速度快,资源占用低。
    • 高度可定制,可以根据需求选择需要的功能模块。
    • 易于嵌入到应用程序中。

    缺点:

    • 功能相对较少,不如 Tomcat 强大。
    • 配置相对灵活,但也意味着需要更多的配置工作。
    • 社区相对较小,遇到问题可能需要自己解决。
  • Undertow:高性能的后起之秀

    Undertow 可以说是 Web 服务器界的“后起之秀”,它以高性能著称,是 Red Hat 开源的一个项目。Undertow 基于 NIO(Non-blocking I/O)技术,可以处理大量的并发请求,非常适合高并发的应用场景。

    优点:

    • 高性能,吞吐量高,延迟低。
    • 轻量级,资源占用低。
    • 支持各种 Web 标准,包括 Servlet、WebSocket 等。

    缺点:

    • 相对较新,不如 Tomcat 和 Jetty 成熟。
    • 配置相对复杂,需要一定的学习成本。
    • 社区相对较小,遇到问题可能需要自己解决。

为了更清晰地了解它们的特点,咱们可以用一个表格来总结一下:

特性 Tomcat Jetty Undertow
重量级
启动速度
资源占用
功能 丰富 较少 丰富
社区 庞大 较小 较小
性能 一般 良好 优秀
配置 复杂 灵活 复杂
适用场景 大型 Web 应用 嵌入式应用、HTTP 客户端 高并发应用

二、嵌入式 Web 服务器的配置

了解了三位“大佬”的特点,接下来咱们就来看看如何在嵌入式环境中配置它们。

  • Tomcat 的配置

    Tomcat 的配置主要通过 server.xml 文件来实现。这个文件位于 Tomcat 的 conf 目录下。

    1. 修改端口号

      在嵌入式环境中,我们可能需要修改 Tomcat 的默认端口号(8080),以避免端口冲突。可以在 server.xml 文件中找到 <Connector> 元素,修改 port 属性即可。

      <Connector port="8081" protocol="HTTP/1.1"
                 connectionTimeout="20000"
                 redirectPort="8443" />
    2. 配置 Context

      Context 代表一个 Web 应用。可以在 server.xml 文件中配置 Context,指定 Web 应用的根目录和访问路径。

      <Context path="/myapp" docBase="myapp" reloadable="true" />

      其中,path 属性指定访问路径,docBase 属性指定 Web 应用的根目录,reloadable 属性指定是否允许 Tomcat 在 Web 应用发生变化时自动重新加载。

    3. 移除不必要的组件

      为了减少 Tomcat 的资源占用,可以移除不必要的组件,比如 Examples、Manager 等。可以在 server.xml 文件中注释掉或删除这些组件的配置。

  • Jetty 的配置

    Jetty 的配置主要通过 jetty.xml 文件来实现。这个文件位于 Jetty 的 etc 目录下。

    1. 修改端口号

      jetty.xml 文件中找到 <New> 元素,修改 port 属性即可。

      <New id="httpConnector" class="org.eclipse.jetty.server.ServerConnector">
          <Arg name="server"><Ref refid="Server" /></Arg>
          <Arg name="factories">
              <Array type="org.eclipse.jetty.server.ConnectionFactory">
                  <Item>
                      <New class="org.eclipse.jetty.server.HttpConnectionFactory">
                          <Arg name="config"><Ref refid="httpConfig"/></Arg>
                      </New>
                  </Item>
              </Array>
          </Arg>
          <Set name="port">8081</Set>
      </New>
    2. 配置 Context

      Jetty 使用 ContextHandler 来管理 Web 应用。可以通过编程的方式创建 ContextHandler,并将其添加到 Jetty 服务器中。

      Server server = new Server(8081);
      WebAppContext context = new WebAppContext();
      context.setContextPath("/myapp");
      context.setResourceBase("myapp");
      server.setHandler(context);
      server.start();
      server.join();
    3. 使用模块化配置

      Jetty 采用模块化设计,可以根据需求选择需要的功能模块。可以通过修改 start.ini 文件来启用或禁用模块。

  • Undertow 的配置

    Undertow 的配置主要通过编程的方式来实现。

    1. 创建 Undertow 服务器

      Undertow server = Undertow.builder()
              .addHttpListener(8081, "localhost")
              .setHandler(Handlers.path()
                      .addPrefixPath("/myapp", Handlers.resource(new ClassPathResourceManager(
                                      UndertowEmbedded.class.getClassLoader(),
                                      UndertowEmbedded.class.getPackage()))
                              .addWelcomeFiles("index.html")))
              .build();
      server.start();
    2. 配置 Handler

      Undertow 使用 Handler 来处理请求。可以使用 Undertow 提供的各种 Handler,比如 ResourceHandler、ServletHandler 等,也可以自定义 Handler。

    3. 使用 Undertow 的 API

      Undertow 提供了丰富的 API,可以用来配置服务器的各种参数,比如线程池大小、缓冲区大小等。

三、嵌入式 Web 服务器的优化

配置好了嵌入式 Web 服务器,接下来咱们就来看看如何优化它们,让它们跑得更快更稳。

  • 通用优化技巧

    1. 减少资源占用

      • 移除不必要的组件或模块。
      • 优化代码,减少内存占用。
      • 使用轻量级的库和框架。
    2. 优化网络连接

      • 启用 Keep-Alive,减少 TCP 连接的开销。
      • 使用 HTTP/2,提高传输效率。
      • 配置连接超时时间,防止连接泄露。
    3. 优化线程池

      • 调整线程池大小,根据实际情况选择合适的线程数。
      • 使用非阻塞 I/O,提高并发能力。
      • 监控线程池状态,及时发现和解决问题。
    4. 启用 Gzip 压缩

      启用 Gzip 压缩可以减少传输的数据量,提高响应速度。

      • Tomcat:在 server.xml 文件中配置 <Connector> 元素,设置 compression 属性为 on

        <Connector port="8081" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443"
                   compression="on"
                   compressionMinSize="2048"
                   compressableMimeType="text/html,text/xml,text/css,text/javascript" />
      • Jetty:在 jetty.xml 文件中配置 GzipHandler

        <New id="gzipHandler" class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
            <Set name="minGzipSize">2048</Set>
            <Set name="mimeTypes">
                <Array type="String">
                    <Item>text/html</Item>
                    <Item>text/xml</Item>
                    <Item>text/css</Item>
                    <Item>text/javascript</Item>
                </Array>
            </Set>
        </New>
      • Undertow:在 Handler 中配置 ResponseEncodingHandler

        Undertow server = Undertow.builder()
                .addHttpListener(8081, "localhost")
                .setHandler(new ResponseEncodingHandler(
                        Handlers.path()
                                .addPrefixPath("/myapp", Handlers.resource(new ClassPathResourceManager(
                                                UndertowEmbedded.class.getClassLoader(),
                                                UndertowEmbedded.class.getPackage()))
                                        .addWelcomeFiles("index.html")),
                        new ContentEncodingRepository()
                                .addEncodingHandler("gzip", new GzipEncodingProvider(), 50, Predicates.suffixes(".html", ".js", ".css"))))
                .build();
        server.start();
  • Tomcat 特有优化技巧

    1. 使用 APR 连接器

      APR(Apache Portable Runtime)是一个高性能的本地库,可以提高 Tomcat 的性能。要使用 APR 连接器,需要安装 APR 库,并在 server.xml 文件中配置 <Connector> 元素。

    2. 禁用自动部署

      自动部署会扫描 Web 应用的目录,如果发现有新的 Web 应用,就会自动部署。在嵌入式环境中,我们通常不需要自动部署,可以禁用它来减少资源占用。

    3. 调整 JVM 参数

      可以调整 JVM 参数,比如堆大小、垃圾回收算法等,来优化 Tomcat 的性能。

  • Jetty 特有优化技巧

    1. 使用 Direct Buffers

      Direct Buffers 可以减少内存拷贝,提高 I/O 性能。可以在 jetty.xml 文件中配置 ServerConnector 元素,设置 useDirectBuffers 属性为 true

    2. 调整 QueuedThreadPool 大小

      QueuedThreadPool 是 Jetty 的线程池,可以调整其大小来优化并发能力。可以在 jetty.xml 文件中配置 QueuedThreadPool 元素,设置 minThreadsmaxThreads 属性。

    3. 使用 NIO 连接器

      Jetty 默认使用 BlockingChannelConnector,可以使用 NIO 连接器来提高性能。

  • Undertow 特有优化技巧

    1. 调整 Buffer Pool 大小

      Undertow 使用 Buffer Pool 来管理内存缓冲区。可以调整 Buffer Pool 大小来优化内存使用。

    2. 调整 IO 线程数

      Undertow 使用 IO 线程来处理 I/O 操作。可以调整 IO 线程数来优化并发能力。

    3. 使用 XNIO

      Undertow 基于 XNIO(Extension NIO)构建,XNIO 是一个高性能的 NIO 框架。

四、代码示例

为了让大家更好地理解,咱们来写几个简单的代码示例。

  • Tomcat 嵌入式示例

    import org.apache.catalina.Context;
    import org.apache.catalina.LifecycleException;
    import org.apache.catalina.startup.Tomcat;
    
    import java.io.File;
    
    public class TomcatEmbedded {
    
        public static void main(String[] args) throws LifecycleException {
    
            Tomcat tomcat = new Tomcat();
            tomcat.setPort(8081);
    
            String webappDirLocation = "src/main/webapp/";
            Context context = tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
            System.out.println("configuring app with basedir: " + new File(webappDirLocation).getAbsolutePath());
    
            tomcat.start();
            tomcat.getServer().await();
        }
    }
  • Jetty 嵌入式示例

    import org.eclipse.jetty.server.Server;
    import org.eclipse.jetty.webapp.WebAppContext;
    
    public class JettyEmbedded {
    
        public static void main(String[] args) throws Exception {
            Server server = new Server(8081);
    
            WebAppContext webAppContext = new WebAppContext();
            webAppContext.setContextPath("/");
            webAppContext.setWar("src/main/webapp"); // or webapp directory
    
            server.setHandler(webAppContext);
    
            server.start();
            server.join();
        }
    }
  • Undertow 嵌入式示例

    import io.undertow.Undertow;
    import io.undertow.Handlers;
    import io.undertow.server.handlers.resource.ClassPathResourceManager;
    
    public class UndertowEmbedded {
    
        public static void main(String[] args) {
            Undertow server = Undertow.builder()
                    .addHttpListener(8081, "localhost")
                    .setHandler(Handlers.path()
                            .addPrefixPath("/", Handlers.resource(new ClassPathResourceManager(
                                            UndertowEmbedded.class.getClassLoader(),
                                            UndertowEmbedded.class.getPackage()))
                                    .addWelcomeFiles("index.html")))
                    .build();
            server.start();
        }
    }

五、总结

好了,各位看官,说了这么多,相信大家对嵌入式 Web 服务器的配置和优化已经有了一定的了解。Tomcat、Jetty 和 Undertow 各有所长,在选择时需要根据实际情况进行权衡。

记住,没有最好的服务器,只有最适合的服务器。希望这篇文章能帮助你在嵌入式 Web 服务器的世界里找到属于你的“最佳搭档”!

最后,送给大家一句名言:

“代码就像笑话,需要解释的时候就不好笑了。”

祝大家编程愉快!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注