目录
参考资料
1 简介
从Tomcat5.0开始提供和支持Embeded版本,即最简化Tomcat Server。Tomcat和Embedded Tomcat版本是同步发布的。
2 下载嵌入式 Tomcat
嵌入式 tomcat 具体表现是一组 jar包,可通过官方下载或者 Maven 仓库下载。
3 代码示例
3.1 实现 Servelt 和 Websocket
3.1.1 建立 maven 工程并引入jar包
<!-- 引入 嵌入式 tomcat 相关jar包-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.68</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>9.0.68</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.68</version>
</dependency>
<!-- 由于没有 jsp 页面,jsp 解析功能由web容器提供 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>9.0.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-log4j</artifactId>
<version>7.0.47</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-annotations-api</artifactId>
<version>9.0.31</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>ecj</artifactId>
<version>3.18.0</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-util</artifactId>
<version>8.5.45</version>
</dependency>
3.1.2 类说明
-
依次创建以下及各类
- TomcatWebContanerBootstrap: 应用入口和调起嵌入式 tomcat,并配置 servelt
- WelcomeServlet : Servlet 服务类
- AnnotationEchoIMServer : 使用 @ServerEndpoint 声明 websocket 端点
- EchoIMServerFilter : 过滤 websocket 端点类
-
类结构:
TomcatWebContanerBootstrap
|
|-- servlet
| |-- WelcomeServlet
|
|-- im
| |-- AnnotationEchoIMServer
| |-- EchoIMServerFilter
如下图:
3.1.3 WelcomeServlet
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* Welcome Servlet
*/
public class WelcomeServlet extends HttpServlet {
/**
* 欢迎语句
*/
private static String HELLO_WORLD = "Hello World , My Frind!";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 响应码 200
resp.setStatus(200);
// 返回 “Hello World , My Frind!”
try(ServletOutputStream out = resp.getOutputStream();){
out.write(HELLO_WORLD.getBytes(StandardCharsets.UTF_8));
out.flush();
}
}
}
3.1.4 AnnotationEchoIMServer
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
/**
* Tomcat Websocket 代码示例 - 基于注解驱动实现服务端
* 主要功能:消息处理器,处理客户端发送过来的消息
*/
@ServerEndpoint("/im/echo/{uid}")
public class AnnotationEchoIMServer {
@OnOpen
public void open(@PathParam("uid") String uid, Session session, EndpointConfig endpointConfig){
// TODO
}
@OnMessage
public void message(String wholeMessage, @PathParam("uid") String pathParam, Session session){
try {
String respMessage = "Server received message : " + wholeMessage;
session.getBasicRemote().sendText(respMessage);
}catch (Exception ex){
}
}
@OnClose
public void close(Session session, CloseReason closeReason, @PathParam("uid") String pathParam){
// TODO
}
@OnError
public void error(Throwable ex, Session session, @PathParam("uid") String pathParam){
// TODO
}
}
3.1.5 EchoIMServerFilter
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
import java.util.Set;
/**
* Tomcat Websocket 代码示例 - 过滤 websocket endpoint
*/
public class EchoIMServerFilter implements ServerApplicationConfig {
/**
* 过滤继承 Endpoint 类实现 websocket的类中能够作为 websocket Endpoint 的类。
* @param endpointClasses Endpoint接口的所有子类
* @return
*/
@Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses) {
// TODO
return null;
}
/**
* 过滤扫描到 @ServerEndpoint 标注的类中能够作为 websocket Endpoint 的类。
* @param scanned 应用中 @ServerEndpoint 标注的类
* @return
*/
@Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
if(scanned.contains(AnnotationEchoIMServer.class)){
return scanned;
}
return null;
}
}
3.1.6 创建程序启动入口 TomcatWebContanerBootstrap
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Wrapper;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.catalina.startup.ContextConfig;
import org.apache.catalina.startup.Tomcat;
import study.lihw.demo.webcontainer.tomcat.servlet.WelcomeServlet;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 嵌入式 tomcat web 容器代码示例
*/
public class TomcatWebContanerBootstrap {
private static Logger logger = Logger.getLogger(TomcatWebContanerBootstrap.class.getName());
// main()应用启动入口
public static void main(String[] args) throws LifecycleException, URISyntaxException {
// 1. 实例化 Tomcat 示例( tomcat 最小启动,Tomcat 类用于嵌入了 tomcat 的应用)
Tomcat tomcat = new Tomcat();
// 2. 配置应用上下文
configContext(tomcat);
// 2. 配置 Servlet
configServlet(tomcat);
// 3. 启动 tomcat 服务
tomcat.start();
logAfterStart(tomcat);
// 4. 同步等待关闭窗口命令关闭
tomcat.getServer().await();
}
/**
* 配置 context
* @param tomcat
*/
private static Context configContext(Tomcat tomcat) throws URISyntaxException {
// 添加应用上下文配置,并制定 webapp 目录为:/G:/***/embedded-web-container/target/classes/
String docPath = TomcatWebContanerBootstrap.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
Context appContext = tomcat.addContext("/", docPath);
// 必须添加 ContextConfig ,否则 SPI 无法加载 WsSci
appContext.addLifecycleListener(new ContextConfig());
}
private static void configServlet(Tomcat server){
/*
1. 在应用上下文 "/" 下添加默认 Servlet,映射 url: /
注意:必须配置 DefaultServlet, webcoket 的 url 依赖。
*/
Wrapper defaultServletWrapper = server.addServlet("/", "default", DefaultServlet.class.getTypeName());
defaultServletWrapper.addMapping("/");
// 2. 在应用上下文 "/" 下配置 Welcome Servlet,映射 url: /index
Wrapper welcomeServletwrapper = server.addServlet("/", "hello", WelcomeServlet.class.getTypeName());
welcomeServletwrapper.addMapping("/index");
}
/**
* 启动日志
* @param tomcat
*/
private static void logAfterStart(Tomcat tomcat){
int port = tomcat.getConnector().getPort();
logger.log(Level.INFO," Embed Tomcat Server listen on port : "+ port);
logger.log(Level.INFO," Embed Tomcat Server Start success.");
}
}
3.1.7 验证
1.启动
四月 02, 2023 11:20:45 下午 org.apache.catalina.core.StandardContext setPath
警告: A context path must either be an empty string or start with a '/' and do not end with a '/'. The path [/] does not meet these criteria and has been changed to []
四月 02, 2023 11:20:47 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
四月 02, 2023 11:20:47 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.68]
四月 02, 2023 11:20:49 下午 org.apache.catalina.startup.ContextConfig getDefaultWebXmlFragment
信息: No global web.xml found
四月 02, 2023 11:21:04 下午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
警告: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [456] milliseconds.
四月 02, 2023 11:21:04 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-nio-8080"]
四月 02, 2023 11:21:04 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]
四月 02, 2023 11:21:05 下午 study.lihw.demo.webcontainer.tomcat.TomcatWebContanerBootstrap logAfterStart
信息: Embed Tomcat Server listen on port : 8080
四月 02, 2023 11:21:05 下午 study.lihw.demo.webcontainer.tomcat.TomcatWebContanerBootstrap logAfterStart
信息: Embed Tomcat Server Start success.
-
postman 连接 localhost:8080/im/echo/black
测试完成