Jetty 嵌入使用

1. 简介

Jetty 提供了一个Web服务器和javax.servlet容器,以及对HTTP/2,WebSocket,OSGi,JMX,JNDI,JAAS和许多其他集成的支持。这些组件是开源的,可用于商业用途和发行。

Jetty有一个口号:不要把应用部署到Jetty上,要把Jetty部署到你的应用里。这句话的意思是把应用打成一个war包部署到Jetty上,不如将Jetty作为应用的一个组件,它可以实例化并像POJO一样。换种说法,在嵌入式模块中运行Jetty意味着把HTTP模块放到你的应用里,这种方法比把你的应用放到一个HTTP服务器里要好。

2. 简单使用

添加 jetty-server 依赖

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-server</artifactId>
  <version>9.4.19.v20190610</version>
</dependency>

继承 AbstractHandler

public class HelloHandler extends AbstractHandler {
    @Override
    public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException {
        // 设置类型,指定编码utf8
        httpServletResponse.setContentType("text/html; charset=utf-8");
        // 设置响应状态吗
        httpServletResponse.setStatus(HttpServletResponse.SC_OK);
        // 写响应数据
        httpServletResponse.getWriter().write("<h1>HelloHandler</h1>");
        // 标记请求已处理,handler链
        request.setHandled(true);
    }
}

创建Server并启动

public class JettySimpleTest {
    public static void main(String[] args) throws Exception {
        // 创建服务器
        Server server = new Server(8001);
        // 设置handler
        server.setHandler(new HelloHandler());
        // 启动应用服务并等待请求
        server.start();
        // 阻塞Jetty server的线程池,直到线程池停止
        server.join();
    }
}

访问 localhost:8001
简单使用

3. 嵌入 web 应用(WebAppContext)

WebAppContext是ServletContextHandler 的扩展,使用标准的web应用组件和web.xml,通过web.xml和注解配置servlet,filter和其它特性。

3.1 hello-war

这里会创建三个项目,然后打成war包。

添加依赖

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
  <scope>provided</scope>
</dependency>

Hello1Servlet

public class Hello1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置响应内容类型
        resp.setContentType("text/html");
        // 实际的逻辑是在这里
        PrintWriter out = resp.getWriter();
        out.println("<h1> hello-war-1 </h1>");
        out.println("<h2> HelloServlet </h2>");
    }
}

web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
  <display-name>Hello1Servlet</display-name>

  <servlet>
    <servlet-name>Hello1Servlet</servlet-name>
    <servlet-class>com.shpun.Hello1Servlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Hello1Servlet</servlet-name>
    <url-pattern>/hello1</url-pattern>
  </servlet-mapping>
</web-app>

index.jsp

<html>
<body>
<h2> hello-war-1 index.jsp </h2>
<h2>Hello World!</h2>
</body>
</html>

hello-war-1 项目结构
hello-war-1 项目结构
hello-war-2 和 hello-war-3 项目结构,和hello-war-1一样。
hello-war-2 和 hello-war-3 项目结构

3.2 jetty-server

添加依赖

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-server</artifactId>
  <version>9.4.19.v20190610</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-servlet</artifactId>
  <version>9.4.19.v20190610</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-webapp</artifactId>
  <version>9.4.19.v20190610</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-deploy</artifactId>
  <version>9.4.19.v20190610</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-annotations</artifactId>
  <version>9.4.19.v20190610</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-servlets</artifactId>
  <version>9.4.19.v20190610</version>
</dependency>
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>apache-jsp</artifactId>
  <version>9.4.19.v20190610</version>
  <type>jar</type>
</dependency>

JettyServer,获取war包地址,使用 WebAppContext 封装。然后再添加到 Server 中。

public class JettyServer {

    private final Server server;

    public JettyServer() throws Exception {
        ClassLoader classLoader = getClass().getClassLoader();

        File tempDir = new File("E:\\IDEA_workspace\\jetty-test\\work\\jetty");

        // war包文件路径
        File helloWar1 = new File("E:\\IDEA_workspace\\jetty-test\\hello-war-1\\target\\hello-war-1.war");
        File helloWar2 = new File("E:\\IDEA_workspace\\jetty-test\\hello-war-2\\target\\hello-war-2.war");
        File helloWar3 = new File("E:\\IDEA_workspace\\jetty-test\\hello-war-3\\target\\hello-war-3.war");

        // Web应用程序上下文处理程序。封装工作目录,war包地址,上下文,类加载器
        WebAppContext helloWar1WebAppContext = buildWebApContext(tempDir, helloWar1,"/hello1", classLoader);
        WebAppContext helloWar2WebAppContext = buildWebApContext(tempDir, helloWar2,"/hello2", classLoader);
        WebAppContext helloWar3WebAppContext = buildWebApContext(tempDir, helloWar3,"/hello3", classLoader);

        // 将三个 WebAppContext 添加到一个 HandlerCollection 中。
        // HandlerCollection 是一个包含多个处理器的集合,按照顺序依次处理
        HandlerCollection handlerCollection = new HandlerCollection();
        handlerCollection.addHandler(helloWar1WebAppContext);
        handlerCollection.addHandler(helloWar2WebAppContext);
        handlerCollection.addHandler(helloWar3WebAppContext);

        // 将 HandlerCollection 压缩
        GzipHandler gzipHandler = new GzipHandler();
        gzipHandler.setIncludedMethods("GET", "POST", "PUT", "DELETE");
        gzipHandler.setHandler(handlerCollection);

        // HandlerCollection会依次调用每一个Handler,即使请求已经被处理了
        ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
        contextHandlerCollection.addHandler(gzipHandler);

		// HandlerList顺序执行handler
        HandlerList handlerList = new HandlerList();
        handlerList.addHandler(contextHandlerCollection);

        // 初始化 Server
        QueuedThreadPool threadPool = new QueuedThreadPool(30);
        threadPool.setName("Web Server");
        server = new Server(threadPool);
        
        server.setHandler(handlerList);

        // HTTP 配置,这是设置请求和返回头的大小
        HttpConfiguration httpConfiguration = new HttpConfiguration();
        httpConfiguration.setRequestHeaderSize(16384);
        httpConfiguration.setResponseHeaderSize(16384);

        // 配置连接器
        // Connector是Jetty中可以直接接受客户端连接的抽象,一个Connector监听Jetty服务器的一个端口
        ServerConnector serverConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
        // 多网卡时使用
        //serverConnector.setHost("192.168.1.2");
        serverConnector.setPort(8001);
        // 设置连接的最大空闲时间
        serverConnector.setIdleTimeout(30000L * 2);

        server.addConnector(serverConnector);

        // 解析jsp方式1:启用基于注释的配置,以确保正确初始化了jsp容器
        Configuration.ClassList classList = Configuration.ClassList.setServerDefault(server);
        classList.addBefore(JettyWebXmlConfiguration.class.getName(), AnnotationConfiguration.class.getName());
    }

    private void start() throws Exception {
        server.start();
    }

    public static void main( String[] args ) throws Exception {
        JettyServer jettyServer = new JettyServer();
        jettyServer.start();
    }

    /**
     * 构建 WebAppContext
     * @param tempDir
     * @param war
     * @param contextPath
     * @param classLoader
     * @return
     * @throws IOException
     */
    private WebAppContext buildWebApContext(File tempDir, File war, String contextPath, ClassLoader classLoader) throws IOException {
        WebAppContext webappContext = new WebAppContext(war.getPath(), contextPath);
        webappContext.setContextPath(contextPath);
        webappContext.setDisplayName(contextPath);

        File workDir = new File(tempDir, war.getName());
        webappContext.setTempDirectory(workDir);
        webappContext.setClassLoader(new WebAppClassLoader(classLoader, webappContext));

        // 解析jsp方式2:
        //webappContext.addBean(new JspStarter(webappContext));
        //webappContext.addServlet(JettyJspServlet.class, "*.jsp");

        return webappContext;
    }
}

Jetty解析jsp目前发现有两种方式
一种是在 Server 启动前,添加

Configuration.ClassList classList = Configuration.ClassList.setServerDefault(server);
classList.addBefore(JettyWebXmlConfiguration.class.getName(), AnnotationConfiguration.class.getName());

一种是在创建 WebAppContext 时添加

webappContext.addBean(new JspStarter(webappContext));
webappContext.addServlet(JettyJspServlet.class, "*.jsp");

还需要 JspStarter

public class JspStarter extends AbstractLifeCycle implements ServletContextHandler.ServletContainerInitializerCaller {
    JettyJasperInitializer sci;
    ServletContextHandler context;

    public JspStarter(ServletContextHandler context) {
        this.sci = new JettyJasperInitializer();
        this.context = context;
        this.context.setAttribute("org.apache.tomcat.JarScanner", new StandardJarScanner());
    }

    @Override
    protected void doStart() throws Exception {
        ClassLoader old = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(context.getClassLoader());
        try {
            sci.onStartup(null, context.getServletContext());
            super.doStart();
        } finally {
            Thread.currentThread().setContextClassLoader(old);
        }
    }
}

测试,三个war包都可正常部署访问
hello1
hello1/hello1
hello2/hello2
hello3/hello3

参考:
Jetty 官方文档
Jetty 官方文档 - 嵌入Jetty
Jetty篇教程 之Jetty 嵌入式服务器
idea下,Jetty采用main方法启动web项目
内嵌式jetty服务器支持jsp
jetty介绍之handler
Jetty Connector学习笔记

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Jetty嵌入式服务器时,你可以通过配置Servlet来实现返回类型转换器。下面是一种可能的配置方法: 1. 创建一个Servlet类,用于处理HTTP请求和响应: ```java import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { // 处理请求并设置响应的内容类型和内容 resp.setContentType("application/json"); resp.getWriter().println("{ \"message\": \"Hello, world!\" }"); } } ``` 2. 创建一个ServletHolder对象并设置它的servlet实例: ```java import org.eclipse.jetty.servlet.ServletHolder; // ... ServletHolder servletHolder = new ServletHolder(new MyServlet()); ``` 3. 创建一个ServletHandler对象并将ServletHolder添加到它的上下文中: ```java import org.eclipse.jetty.servlet.ServletContextHandler; // ... ServletContextHandler servletContextHandler = new ServletContextHandler(); servletContextHandler.addServlet(servletHolder, "/"); ``` 4. 创建一个Jetty服务器实例并将ServletHandler设置为它的处理程序: ```java import org.eclipse.jetty.server.Server; // ... Server server = new Server(8080); server.setHandler(servletContextHandler); ``` 5. 启动服务器: ```java server.start(); ``` 这样,当你访问http://localhost:8080/时,Jetty服务器将返回类型设置为application/json,并以JSON格式返回响应内容。 请注意,这只是一种基本的示例配置方式,你还可以根据你的需求进行更详细的配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值