不安分的黑娃
踏踏实实,坚持学习,慢慢就懂了~

参考资料

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 类说明

  1. 依次创建以下及各类

    • TomcatWebContanerBootstrap: 应用入口和调起嵌入式 tomcat,并配置 servelt
    • WelcomeServlet : Servlet 服务类
    • AnnotationEchoIMServer : 使用 @ServerEndpoint 声明 websocket 端点
    • EchoIMServerFilter : 过滤 websocket 端点类
  2. 类结构:

TomcatWebContanerBootstrap 
  |
  |--  servlet
  |     |-- WelcomeServlet
  |
  |-- im
  |     |-- AnnotationEchoIMServer
  |     |-- EchoIMServerFilter

如下图:
image

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.


  1. 访问 http://localhost:8080/index
    image

  2. postman 连接 localhost:8080/im/echo/black
    image
    测试完成

posted on 2023-04-02 23:24  不安分的黑娃  阅读(334)  评论(0编辑  收藏  举报