Jetty嵌入式Web容器攻略

来源:http://www.cnblogs.com/8hao/archive/2016/03/01/5230795.html
-Advertisement-
Play Games

Jetty是一個用 Java 實現、開源、基於標準的,並且具有豐富功能的 Http 伺服器和 Web 容器。Jetty中應用最廣泛的一項功能就是可以作為嵌入式Web容器。 在開發階段,可以使用Jetty在Eclipse里直接啟動應用,而不是像Tomcat那樣繁瑣,先把幾十兆應用打包,然後再複製到某個


Jetty是一個用 Java 實現、開源、基於標準的,並且具有豐富功能的 Http 伺服器和 Web 容器。Jetty中應用最廣泛的一項功能就是可以作為嵌入式Web容器。

  • 在開發階段,可以使用Jetty在Eclipse里直接啟動應用,而不是像Tomcat那樣繁瑣,先把幾十兆應用打包,然後再複製到某個目錄後再啟動。
  • 在測試階段,可以直接在測試用例中啟動Jetty,而不是先將應用打包部署到容器。
  • 在運行階段,可以將war包配置成直接能夠運行的應用

本文將著重介紹如何配置使用Jetty的嵌入式Web容器功能,關於Jetty的基本配置和功能請參考http://www.ibm.com/developerworks/cn/web/wa-lo-jetty/

一、開發階段
1、使用maven啟動Jetty

我們修改了源碼的時候eclipse會自動編譯,Jetty Maven Plugin插件發現編譯文件有變化後會自動更新到jetty容器中,非常方便我們進行開發。

首先定義Jetty的版本屬性

1 2 3 <properties>  <jetty.version>8.1.9.v20130131</jetty.version>  </properties>

然後引入Jetty依賴

1 2 3 4 5 6 7 8 9 10 11 12 13 <!-- jetty -->  <dependency>  <groupId>org.eclipse.jetty.aggregate</groupId>  <artifactId>jetty-webapp</artifactId>  <version>${jetty.version}</version>  <scope>test</scope>  </dependency>  <dependency>  <groupId>org.eclipse.jetty</groupId>  <artifactId>jetty-jsp</artifactId>  <version>${jetty.version}</version>  <scope>test</scope>  </dependency>

配置Jetty Maven Plugin插件,示例如下

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <plugin>  <groupId>org.mortbay.jetty</groupId>  <artifactId>jetty-maven-plugin</artifactId>  <version>${jetty.version}</version>  <configuration>  <systemProperties>  <systemProperty>  <name>spring.profiles.active</name>  <value>development</value>  </systemProperty>  </systemProperties>  <useTestClasspath>true</useTestClasspath>    <webAppConfig>  <contextPath>/${project.artifactId}</contextPath>  </webAppConfig>  </configuration>  </plugin>

該配置運行jetty並指定spring的profile為development,同時設定web應用的上下文地址與應用本身的artifactId一致。

執行如下命令啟動Jetty,即可通過http://localhost:8080/${project.artifactId}訪問Web應用。

1 mvn jetty:run

Jetty Maven Plugin插件支持多個maven goals,最常用的就是run,下麵的參數支持大部分的goals

(1)配置Jetty容器(支持所有goals)

  • <connectors>:可選參數,配置org.eclipse.jetty.server.Connector(Jetty埠監聽器)列表,如果不指定該參數,將會連接預設的8080埠。
  • <jettyXml>:可選參數,指定Jetty配置文件的路徑
  • <scanIntervalSeconds>:可選參數,配置Web應用掃描的暫停時間,Web應用掃描如果發現修改了程式,會自動重新部署。該參數預設值為0,即不啟動熱部署
  • <systemProperties>:可選參數,設置插件執行時的系統參數,比如上面的配置示例中指定了spring的profile為development,如果不設置該參數,就需要配置maven與spring的profile一致,同時在mvn命令中增加-Pdevelopment選項,或者直接在spring配置文件中設置spring.profiles.active為development
  • <systemPropertiesFile>:可選參數,設置系統參數配置文件的位置,將會批量執行其中的系統參數配置
  • <loginServices>:可選參數,配置org.eclipse.jetty.security.LoginService實現類的列表。
  • <requestLog>:可選參數,配置請求日誌介面:org.eclipse.jetty.server.RequestLog的實現類,配置請求日誌的處理格式,

比如org.mortbay.jetty.NCSARequestLog就是一個NCSA格式((美國)國家超級計算技術應用中心 (NCSA) 公用格式,是常用的標準日誌格式)的實現。

(2)配置Web應用程式(不支持run-forked、stop兩個goals)

  • <webApp>:從jetty6.1.6rc0起使用webAppConfig,web應用程式配置根節點
  • <contextPath>:設置web應用程式的context路徑,預設情況下,它被設置成該項目的pom.xml的<artifactId>
  • <descriptor>:設置web應用程式主配置文件web.xml的路徑,預設該配置文件位於WEB-INF目錄下
  • <defaultsDescriptor>:設置先於web.xml執行的webdefault.xml配置文件的路徑
  • <overrideDescriptor>:設置在web.xml讀取之後執行的配置文件,使用該參數可以覆蓋或增加web.xml中的配置
  • <tempDirectory>:Web應用的臨時目錄,Jetty可以在此目錄編譯jsp文件或者複製jar包,預設路徑為${project.build.outputDirectory}/tmp
  • <baseResource>:指定Web應用靜態資源所在的路徑,預設路徑為src/main/webapp
  • <resourceBases>:指定多個Web應用靜態資源所在的路徑,使用逗號分隔
  • <baseAppFirst>:可選參數,預設值為true,控制是否可以在Web應用的原始資源之前或之後疊加多個war包
  • <jettyEnvXml>:可選參數,指定jetty-env.xml配置文件的路徑
  • <containerIncludeJarPattern>:jetty-8.1.x之後的版本可以使用,可選參數,配置載入到Jetty容器 Classloader中的Jar包的路徑或匹配模式,符合條件的jar包將會被檢測META-INF、資源、tld和類的繼承關係
  • <webInfIncludeJarPattern>:jetty-8.1.x之後的版本可以使用,可選參數,配置載入到Web應用程式的Classloader(WEB-INF classpath)中的Jar包的路徑或匹配模式,符合條件的jar包將會被檢測META-INF、資源、tld和類的繼承關係
  • <contextXml>:可選參數,指定context xml配置文件的路徑

run goals將會啟動Jetty並運行應用程式,不需要應用程式編譯成war包。另外run還支持webapp節點的其它屬性:

  • <classesDirectory>:Web應用程式類編譯後的路徑
  • <testClassesDirectory>:Web應用程式單元測試類編譯後的路徑,預設值為${project.build.testOutputDirectory}.
  • <useTestScope>:Jetty-7之前的版本參數名稱為useTestClasspath,如果設置為true,開啟測試模式,<testClassesDirectory>中指定的類及其依賴將首先被載入到classpath中,預設值為false
  • <useProvidedScope>:如果設置為true,依賴範圍標示為“provided”的依賴將被載入到容器的classpath中,該參數很少使用。
  • <webAppSourceDirectory>:Web應用程式靜態資源路徑,預設值為${basedir}/src/main/webapp
  • <scanTargets>:配置除了插件自動掃描的位置外,其它需要掃描的目錄或文件列表
  • <scanTargetPatterns>:配置除了插件自動掃描的位置外,其它需要掃描的目錄或文件的匹配模式
  • <skip>:預設值為false,如果設置為true,將會停止執行插件

Jetty Maven Plugin插件支持的其它goals簡介如下(詳見http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin):

  • run-war:將Web應用程式打包成war包並部署到Jetty中。
  • run-exploded:使用war exploded模式(文件夾模式)將Web應用程式打包並部署到Jetty中
  • deploy-war:功能與run-war類似,區別就是maven生命周期中不包含package階段
  • run-forked:jetty-7.5.2之後的版本可用,強迫Jetty使用一個新的JVM啟動應用程式
  • start:jetty-7.6.0之後的版本可用,一般在配合插件中的execution節點使用,test-compile階段之後才執行構建,確保必要的類及文件都生成好了。一般用於集成測試時啟動Jetty,本文第二部分測試階段會有詳細介紹
  • stop:關閉運行中的Jetty容器

2、在java中啟動Jetty
SpringSide4中封裝了Jetty的操作提供了工具類JettyFactory ,讓我們可以很簡單的啟動Jetty容器,JettyFactory代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 /**  * Copyright (c) 2005-2012 springside.org.cn  *  * Licensed under the Apache License, Version 2.0 (the "License");  */  package org.springside.modules.test.jetty;    import java.util.List;    import org.apache.commons.lang3.StringUtils;  import org.eclipse.jetty.server.Connector;  import org.eclipse.jetty.server.Server;  import org.eclipse.jetty.server.nio.SelectChannelConnector;  import org.eclipse.jetty.webapp.WebAppClassLoader;  import org.eclipse.jetty.webapp.WebAppContext;    import com.google.common.collect.Lists;    /**  * 創建Jetty Server的工廠類.  *  * @author calvin  */  public class JettyFactory {    private static final String DEFAULT_WEBAPP_PATH = "src/main/webapp";  private static final String WINDOWS_WEBDEFAULT_PATH = "jetty/webdefault-windows.xml";    /**  * 創建用於開發運行調試的Jetty Server, 以src/main/webapp為Web應用目錄.  */  public static Server createServerInSource(int port, String contextPath) {  Server server = new Server();  // 設置在JVM退出時關閉Jetty的鉤子。  server.setStopAtShutdown(true);    SelectChannelConnector connector = new SelectChannelConnector();  connector.setPort(port);  // 解決Windows下重覆啟動Jetty居然不報告埠衝突的問題.  connector.setReuseAddress(false);  server.setConnectors(new Connector[] { connector });    WebAppContext webContext = new WebAppContext(DEFAULT_WEBAPP_PATH, contextPath);  // 修改webdefault.xml,解決Windows下Jetty Lock住靜態文件的問題.  webContext.setDefaultsDescriptor(WINDOWS_WEBDEFAULT_PATH);  server.setHandler(webContext);    return server;  }    /**  * 設置除jstl-*.jar外其他含tld文件的jar包的名稱.  * jar名稱不需要版本號,如sitemesh, shiro-web  */  public static void setTldJarNames(Server server, String... jarNames) {  WebAppContext context = (WebAppContext) server.getHandler();  List<String> jarNameExprssions = Lists.newArrayList(".*/jstl-[^/]*\\.jar$", ".*/.*taglibs[^/]*\\.jar$");  for (String jarName : jarNames) {  jarNameExprssions.add(".*/" + jarName + "-[^/]*\\.jar$");  }    context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",  StringUtils.join(jarNameExprssions, '|'));    }    /**  * 快速重新啟動application,重載target/classes與target/test-classes.  */  public static void reloadContext(Server server) throws Exception {  WebAppContext context = (WebAppContext) server.getHandler();    System.out.println("[INFO] Application reloading");  context.stop();    WebAppClassLoader classLoader = new WebAppClassLoader(context);  classLoader.addClassPath("target/classes");  classLoader.addClassPath("target/test-classes");  context.setClassLoader(classLoader);    context.start();    System.out.println("[INFO] Application reloaded");  }  }

JettyFactory包含三個方法

  • createServerInSource:以src/main/webapp為Web應用目錄創建Jetty WebServer,確保jvm退出時關閉Jetty,在同一個埠啟動多個jetty時報告埠衝突,並解決了javascript、css等靜態文件被jetty鎖定而不能修改的問題。
  • setTldJarNames:Jetty,tomcat等web容器通常都會對classloader做擴展,Jetty中的org.mortbay.jetty.webapp.WebAppClassLoader負責載入一個Web應用context中的應用類。
  • Jetty的jsp處理引擎來自於Glassfish,要求JSF標簽必須位於Jetty容器的classpath中,不能位於Web應用的classpath中,而Jetty的WebAppClassLoader優先使用父classloader載入類,導致tld文件都被載入到父classloader中,在Jetty的classpath中根本掃描不到,所以會出現找不到tld文件的情況。setTldJarNames方法可以設置將包含tld的jar包載入到Jetty的classpath中。
  • reloadContext:重新載入Jetty的context

調用JettyFactory在Jetty中運行調試Maven Web應用的示例代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package org.springside.examples.quickstart;    import org.eclipse.jetty.server.Server;  import org.springside.modules.test.jetty.JettyFactory;  import org.springside.modules.test.spring.Profiles;    /**  * 使用Jetty運行調試Web應用, 在Console輸入回車快速重新載入應用.  *  * @author calvin  */  public class QuickStartServer {    public static final int PORT = 8080;  public static final String CONTEXT = "/quickstart";  public static final String[] TLD_JAR_NAMES = new String[] { "sitemesh", "spring-webmvc", "shiro-web",  "springside-core" };    public static void main(String[] args) throws Exception {  // 設定Spring的profile  Profiles.setProfileAsSystemProperty(Profiles.DEVELOPMENT);    // 啟動Jetty  Server server = JettyFactory.createServerInSource(PORT, CONTEXT);  JettyFactory.setTldJarNames(server, TLD_JAR_NAMES);    try {  server.start();    System.out.println("[INFO] Server running at http://localhost:" + PORT + CONTEXT);  System.out.println("[HINT] Hit Enter to reload the application quickly");    // 等待用戶輸入回車重載應用.  while (true) {  char c = (char) System.in.read();  if (c == '\n') {  JettyFactory.reloadContext(server);  }  }  } catch (Exception e) {  e.printStackTrace();  System.exit(-1);  }  }  }

上段代碼還提供了通過捕獲在console中輸入的回車自動重新載入上下文,並重新載入Class文件,提高了響應速度。

在執行main方法過程中如果發生如下錯誤:

class “javax.servlet.HttpConstraintElement”‘s signer information does not match signer information of other classes in the same package

通過執行如下命令檢查依賴

1 mvn dependency:tree -Dverbose|grep servlet

檢查結果如圖

發現是因為Jetty8版本的包的依賴包org.eclipse.jetty.orbit.javax.servlet3.0.jar提供了javax.servlet.HttpConstraintElement類,而javax.servlet.servlet-api.jar的依賴包javax.servlet.javax.servlet-api-3.0.1.jar也提供了javax.servlet.HttpConstraintElement類,兩者發生了衝突。可以使用7.6.14.v20131031版本的Jetty解決此問題。

二、測試階段

在功能測試或集成測試階段,希望在測試開始時自動運行Jetty載入項目進行測試,測試完成時停止Jetty容器。Jetty Maven Plugin插件可以幫助我們完成這種自動化工作。配置示例如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <plugin>  <groupId>org.mortbay.jetty</groupId>  <artifactId>jetty-maven-plugin</artifactId>  <configuration>  <scanIntervalSeconds>10</scanIntervalSeconds>  <stopKey>foo</stopKey>  <stopPort>9999</stopPort>  </configuration>  <executions>  <execution>  <id>start-jetty</id>  <phase>pre-integration-test</phase>  <goals>  <goal>start</goal>  </goals>  <configuration>  <scanIntervalSeconds>0</scanIntervalSeconds>  <daemon>true</daemon>  </configuration>  </execution>  <execution>  <id>stop-jetty</id>  <phase>post-integration-test</phase>  <goals>  <goal>stop</goal>  </goals>  </execution>  </executions> </plugin>

在上述配置中,通過execution來自定義運行階段:

  • 在pre-integration-test階段運行start goals啟動Jetty容器
  • 在post-integration-test階段運行stop goals停止Jetty容器。

使用<daemon>true</daemon>配置選項來預防Jetty無限期運行,迫使它只在執行Maven時才運行。

三、運行階段

為了能夠創建可以直接運行的war包,需要把jetty jar包解開,將其中的class直接編譯到war包中,並需要在war中提供一個可以創建並運行Jetty的Main方法。本文提供兩種實現方法:

方法一
SpringSide4中提供了一種實現方法,稍加修改優化後步驟如下:

1、使用maven-assembly-plugin重新打包

maven-assembly-plugin插件能將應用程式打包成指定格式的分發包,更重要的是能夠自定義包含/排除指定的目錄或文件。

為方便操作,單獨建立一個Maven Profile用於打包,配置如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <profile>  <id>standalone</id>  <build>  <plugins>  <plugin>  <groupId>org.apache.maven.plugins</groupId>  <artifactId>maven-assembly-plugin</artifactId>  <executions>  <execution>  <phase>package</phase>  <goals>  <goal>single</goal>  </goals>  <configuration>  <descriptors>  <descriptor>assembly-standalone.xml</descriptor>  </descriptors>  <archive>  <manifest>
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 好了,還是這張圖,還是一樣的Hello world。 因為本章其實很多都是講一些命令行編譯啊什麼鬼的配置類的東西,要用的時候直接百度或者回頭查書就可以了, 所以瞭解一下也就行了,也沒有記錄下來,接下來講得只是我認為很有用的東西。 關於引用 請看上圖,MyTest程式集下麵有個引用,引用裡面大家都知道
  • 上次業務邏輯和展示層的架構都寫了,可以開始進行具體功能的實現,這次先實現管理員的登錄、驗證和註銷功能。 一、業務邏輯層 1、實現256散列加密方法。 Ninesky.Core【右鍵】-> 添加->文件夾,輸入文件夾名General。 General文件夾【右鍵】->添加->類,輸入類名Securit...
  • 一. 在調試時,不要使用調試程式的X號關掉程式,而是要用VS自帶的停止調試的介面,即那個小方塊。不然下次調試會出現異常,若真出現這種情況,可以右鍵項目名,點擊清理。 二. Visible屬性 是“可見”的意思,若在屬性里設置 this.visible=false;會使當前控制項隱藏, 若在控制條件里設
  • MVVMlight在UWP開發中的使用
  • 在ASP.NET2.0開始,提供了母版頁的功能。母版頁由一個母版頁和多個內容頁構成。母版頁的主要功能是為ASP.NET應用程式中的頁面創建相同的佈局和界面風格。母版頁的使用與普通頁面類似,可以在其中放置文件或者圖形、任何HTML控制項和Web控制項、後置代碼等。 母版頁僅僅是一個頁面模板,單獨的母版頁是
  • 繼續,前面已經實現了C#調用Windows API實現了彈出對話框功能。使用了User32.dll文件,主要代碼如下:[DllImport("User32.dll")]public static extern int MessageBox(int h, string m, string c, int
  • 以下為本次實踐代碼: 1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Linq; 5 using System.Reflection; 6 using
  • 最近項目中有用到Webservice,研究了Spring與CXF整合的官方文檔(其實官方文檔說的清楚了,建議大伙還是看官方文檔,都是很簡單英文單詞),所以就有了下麵的demo,相信大伙都能看懂 用的主要架構為Maven + Spring + CXF + IDEA,廢話就不多說了,先看下整個個項目結構...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...