好的,没问题!咱们这就来聊聊嵌入式 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
目录下。-
修改端口号
在嵌入式环境中,我们可能需要修改 Tomcat 的默认端口号(8080),以避免端口冲突。可以在
server.xml
文件中找到<Connector>
元素,修改port
属性即可。<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
-
配置 Context
Context 代表一个 Web 应用。可以在
server.xml
文件中配置 Context,指定 Web 应用的根目录和访问路径。<Context path="/myapp" docBase="myapp" reloadable="true" />
其中,
path
属性指定访问路径,docBase
属性指定 Web 应用的根目录,reloadable
属性指定是否允许 Tomcat 在 Web 应用发生变化时自动重新加载。 -
移除不必要的组件
为了减少 Tomcat 的资源占用,可以移除不必要的组件,比如 Examples、Manager 等。可以在
server.xml
文件中注释掉或删除这些组件的配置。
-
-
Jetty 的配置
Jetty 的配置主要通过
jetty.xml
文件来实现。这个文件位于 Jetty 的etc
目录下。-
修改端口号
在
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>
-
配置 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();
-
使用模块化配置
Jetty 采用模块化设计,可以根据需求选择需要的功能模块。可以通过修改
start.ini
文件来启用或禁用模块。
-
-
Undertow 的配置
Undertow 的配置主要通过编程的方式来实现。
-
创建 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();
-
配置 Handler
Undertow 使用 Handler 来处理请求。可以使用 Undertow 提供的各种 Handler,比如 ResourceHandler、ServletHandler 等,也可以自定义 Handler。
-
使用 Undertow 的 API
Undertow 提供了丰富的 API,可以用来配置服务器的各种参数,比如线程池大小、缓冲区大小等。
-
三、嵌入式 Web 服务器的优化
配置好了嵌入式 Web 服务器,接下来咱们就来看看如何优化它们,让它们跑得更快更稳。
-
通用优化技巧
-
减少资源占用
- 移除不必要的组件或模块。
- 优化代码,减少内存占用。
- 使用轻量级的库和框架。
-
优化网络连接
- 启用 Keep-Alive,减少 TCP 连接的开销。
- 使用 HTTP/2,提高传输效率。
- 配置连接超时时间,防止连接泄露。
-
优化线程池
- 调整线程池大小,根据实际情况选择合适的线程数。
- 使用非阻塞 I/O,提高并发能力。
- 监控线程池状态,及时发现和解决问题。
-
启用 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 特有优化技巧
-
使用 APR 连接器
APR(Apache Portable Runtime)是一个高性能的本地库,可以提高 Tomcat 的性能。要使用 APR 连接器,需要安装 APR 库,并在
server.xml
文件中配置<Connector>
元素。 -
禁用自动部署
自动部署会扫描 Web 应用的目录,如果发现有新的 Web 应用,就会自动部署。在嵌入式环境中,我们通常不需要自动部署,可以禁用它来减少资源占用。
-
调整 JVM 参数
可以调整 JVM 参数,比如堆大小、垃圾回收算法等,来优化 Tomcat 的性能。
-
-
Jetty 特有优化技巧
-
使用 Direct Buffers
Direct Buffers 可以减少内存拷贝,提高 I/O 性能。可以在
jetty.xml
文件中配置ServerConnector
元素,设置useDirectBuffers
属性为true
。 -
调整 QueuedThreadPool 大小
QueuedThreadPool 是 Jetty 的线程池,可以调整其大小来优化并发能力。可以在
jetty.xml
文件中配置QueuedThreadPool
元素,设置minThreads
和maxThreads
属性。 -
使用 NIO 连接器
Jetty 默认使用 BlockingChannelConnector,可以使用 NIO 连接器来提高性能。
-
-
Undertow 特有优化技巧
-
调整 Buffer Pool 大小
Undertow 使用 Buffer Pool 来管理内存缓冲区。可以调整 Buffer Pool 大小来优化内存使用。
-
调整 IO 线程数
Undertow 使用 IO 线程来处理 I/O 操作。可以调整 IO 线程数来优化并发能力。
-
使用 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 服务器的世界里找到属于你的“最佳搭档”!
最后,送给大家一句名言:
“代码就像笑话,需要解释的时候就不好笑了。”
祝大家编程愉快!