Jetty 跟 Tomcat 一樣,都支援標準 Servlet 及 JavaEE 規範,但 Jetty 架構比 Tomcat 簡單,可以獨立運作,也可以用 embedded 的方式嵌入 project 中。目前 Jetty 支援 Servlet Spec 3.1 及 JSP 2.3,有部分規範是以模組的方式支援,可藉由設定的方式 enable/disable。
在專案配置 Jetty 只需要以 Maven POM 引用 jetty,就可以用嵌入的方式啟動 Jetty。
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.12.v20180830</version>
</dependency>
</dependencies>
也可以直接下載 Jetty,以 standalone 方式啟動,下載 Jetty 有兩種,第一種是標準的完整的 Jetty,裡面包含了 modules 以及一個 demo server 配置。另一種是 jetty-home,是最小的 package,提供給進階使用者使用。
要啟動 Jetty 可執行下載的 $JETTY_HOME/bin 目錄中的 ./jetty.sh start
,只要用 ./jetty.sh stop
停止 Jetty。
如果要以 console 模式啟動 jetty,可切換到 $JETTY_HOME 目錄,然後直接以 java 執行
java -jar start.jar
預設都是提供 http://localhost:8080 的服務,因為預設沒有部署任何 webapp,所以連接該網址後會得到 404 Error。
Jetty 裡面有個 Demo Base 配置範例,可以切換到該目錄,啟動範例
cd demo-base/
java -jar ../start.jar
可用以下指令,檢查 demo base 裡面的 modules 及 config
cd demo-base/
java -jar ../start.jar --list-modules
java -jar ../start.jar --list-config
Configuration
- jetty.home
定義 Jetty 主程式、lib、default modules與 default XML files 的目錄,這是不會修改異動的部分 - jetty.base
定義了 Jetty Server、configurtion、logs與 webapps 目錄
這兩個 properties 可透過 command line 設定,或是由環境變數 $JETTY_HOME, $JETTY_BASE
決定
以下是建立一個新的 jetty.base 目錄,然後 enable HTTP connector 與 web app deployer modules,並複製並部署 demo webapp
# JETTY_HOME 設定為下載 Jetty Distribution 解壓縮後的目錄
JETTY_HOME=~/java/jetty
JETTY_BASE=/tmp/mybase
mkdir $JETTY_BASE
cd $JETTY_BASE
直接啟動,會得到 error
$ java -jar $JETTY_HOME/start.jar
WARNING: Nothing to start, exiting ...
$ java -jar $JETTY_HOME/start.jar --create-startd
MKDIR : ${jetty.base}/start.d
INFO : Base directory was modified
$ java -jar $JETTY_HOME/start.jar --add-to-start=http,deploy
INFO : webapp transitively enabled, ini template available with --add-to-start=webapp
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : security transitively enabled
INFO : servlet transitively enabled
INFO : http initialized in ${jetty.base}/start.d/http.ini
INFO : threadpool transitively enabled, ini template available with --add-to-start=threadpool
INFO : deploy initialized in ${jetty.base}/start.d/deploy.ini
MKDIR : ${jetty.base}/webapps
INFO : Base directory was modified
$ cp $JETTY_HOME/demo-base/webapps/async-rest.war webapps/ROOT.war
$ java -jar $JETTY_HOME/start.jar
在 command line 可直接修改 http port
java -jar $JETTY_HOME/start.jar jetty.http.port=8081
但這只是暫時的設定,實際上設定值會用以下順序決定
start.d/http.ini
該檔案是 http module 的設定參數modules/httpd.mod
定義料 http module 並指定使用etc/jetty-http.xml
設定檔jetty.http.port
屬性,是由/etc/jetty-http.xml
指定使用該屬性
後續再增加 SSL 及 http2
$ java -jar $JETTY_HOME/start.jar --add-to-start=https,http2
$ java -jar $JETTY_HOME/start.jar
啟動後,可使用 https://localhost:8443/
可用 --help 查詢所有 command line 指令
java -jar $JETTY_HOME/start.jar --help
deployment
部署 Jetty Webapp 有幾種方式,而且都可以在不停止 Jetty 的條件下,直接部署該 webapp
- 一個目錄 (ex: example/) 裡面有 WEB-INF 目錄,以及 web.xml,將目錄放到 $JETTY_BASE 的 webapps 目錄中,就可以部署該 webapp
- example.war
- 一個獨立的 XML 檔案,裡面定義 webapp 的相關資訊。可參考 demo-base/test.xml 為範例
在剛剛的 /tmp/mybase
新的 $JETTY_BASE 目錄中,如果要部署一個 example webapp,裡面有 JSP 網頁,必須先增加 jsp module support
$ java -jar $JETTY_HOME/start.jar --add-to-start=jsp
example 目錄結構包含一個目錄,兩個檔案
example/
index.jsp
WEB-INF/
web.xml
web.xml 就是很單純的標準 webapp
<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
version="4.0">
</web-app>
啟動 jetty 後,將 example 複製到 /tmp/mybase/webapps 裡面,可看到 example hot deploy 的 log
$ java -jar $JETTY_HOME/start.jar
.....
oejsh.ContextHandler:Scanner-0: Started o.e.j.w.WebAppContext@7a5904a3{ex,/ex,file:///private/tmp/mybase/webapps/example/,AVAILABLE}{/example}
另外要注意的是,在 webapps 裡面如果有 ROOT 目錄,或是 ROOT.war,這個是 jetty server 的 default web context application。也就是 http://localhost:8080/ 連線取得的網頁。
Configuration
如何設定 jetty
POJO configuration
直些撰寫 java code 設定 jetty。或是使用 etc/jetty.xml,這是 main jetty XML config。或是利用 IoC framework (spring) 初始化 jetty objects as Spring beans
Jetty Start Configuration Files
jetty distribution 使用以下設定檔,透過 start.jar 初始化 jetty
ini files
jetty 利用 command line 讀取
$JETTY_BASE/start.ini and/or $JETTY_BASE/start.d/*.ini
files,產生 command line arguments
- --module=name 啟用 module
- name=value 用在參數化的 Jetty IoC XML
- XML files: Jetty IoC(Spring) XML 格式
- 標準 property file,包含附加的 start properties
- 其他 start.jar options (
java -jar start.jar --help
) - 一些 JVM options ,以 --exec 整合,例如 -Xbootclasspath
mod files
$JETTY_HOME/modules/*.mod files,以 --module=name 啟用,每個 mod 都定義了
- module dependencies for ordering and activation
- 需增加的 libraries
- module 增加的 command line 參數
- 啟用 module 需要的檔案
- template ini,可用
--add-to-start=name
啟用
XML files
Jetty IoC XML format 或是 Spring IoC format,通常放在
$JETTY_HOME/etc/
,附加的 XML 放在$JETTY_BASE/etc/
以下是這些設定檔的關係圖
在 Jetty 需要設定什麼?
Server
核心設定檔為 /etc/jetty.xml,可加上其他 server configurations:
ThreadPool
server instance 提供了一個 ThreadPool instance,這是 jetty server components 使用的預設 Executor service,可在 start.ini 或 start.d/server.ini 調整 max/min sizeHandlers
jetty 只能有一個 Handler instance 處理 incomping HTTP request,預設 handler tree 設定在 etc/jetty.xml,包含了 a context Handler Collection 及 Default Handler。
Context Handler Collection 由 context path 選擇 handler,也就是 deployed Context Handler 及 Web Application Contexts
Default Handler 無法處理的 request 會產生 404 page,可增加其他 handlers(ex: jetty-rewrite.xml, jetty-requestlog.xml) 或增加 hot deploy handlers (ex: jetty-deploy.xml)
Server Attributes
server 會儲存 attribute map of strings,給 components 使用,如果 value objects 實作了 LifeCycle interface,就會 started/stopped with the server,通常 server attributes 是儲存 server-wide default valuesServer fields
可設定在 start.ini 或 start.d/server.init,控制 HTTP responses 的 dates, versionsConnectors
接收 HTTP 或其他 protocol 的 connectionsServices
儲存 service objects,通常會以 LifeCycle beans 存在,例如 Login Services 及 DataSources。以 server level 設定,在 webapp 使用。
Connector
network endpoint,接收某個 protocol 的 connection,標準 protocol 為 http.ini, https.ini, jetty-http2.ini
- Port
jetty.http.port (jetty.ssl.port),預設為 8080 (8443) Host
jetty.host 預設為 0.0.0.0Idle Timeout
在 connector 動作前,可 idle 多少 ms,否則就 close connectionHTTP Configuration
包含 http, https, http2SSL Context Factory
TLS connector type (https, http2) 設定 keystore 及 truststore
jetty 9 是以單一 ServerConnector type,他是 NIO based,並以 Connection Factories 處理多個 protocols
- Port
Contexts
contextPath
URL prefix,例如 /foo 可處理 /foo, /foo/index.html ... 這些 URL。 / 稱為 root contextvirtualHost
context 可設定多個 virtual hosts,virtual host 不需要設定 network parameters。virtual host 代表 IP 的 name service aliasclassPath
context 可有自訂的 classpath,該 context 內執行的 handler,有增加該 classpath 的 thread context classloader。標準 webapp 會增加 WEB-INF/lib 及 WEB-INF/classes 這兩個目錄到 classpathattributes
ex: javax.servlet.context.tempdir 用在 webapp 使用 File instance 的 temp dirresourceBase
包含 static resource for the context,圖片或 html
Context Configuration by API
在 embedded server,是呼叫 ContextHandler API 進行 context 設定
package org.eclipse.jetty.embedded;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
public class OneContext
{
public static void main( String[] args ) throws Exception
{
Server server = new Server( 8080 );
// Add a single handler on context "/hello"
ContextHandler context = new ContextHandler();
context.setContextPath( "/hello" );
context.setHandler( new HelloHandler() );
// Can be accessed using http://localhost:8080/hello
server.setHandler( context );
// Start the server
server.start();
server.join();
}
}
Context Configuration by IoC XML
以下 XML 設定,提供 jetty distribution 的 javadoc context
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC
"-//Mort Bay Consulting//DTD Configure//EN"
"http://www.eclipse.org/jetty/configure_9_3.dtd">
<!--
Configure a custom context for serving javadoc as static resources
-->
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
<Set name="contextPath">/javadoc</Set>
<Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/javadoc/</Set>
<Set name="handler">
<New class="org.eclipse.jetty.server.handler.ResourceHandler">
<Set name="welcomeFiles">
<Array type="String">
<Item>index.html</Item>
</Array>
</Set>
<Set name="cacheControl">max-age=3600,public</Set>
</New>
</Set>
</Configure>
Configuring Web Applications
jetty 用以下方式處理 WAR application
- classpath 包含 WEB-INF/lib, WEB-INF/classes
- WEB-INF/web.xml 定義 init parameters, filters, servlets, listeners, security constraints, welcome files, resources
- annotations 處理 WEB-INF/lib 是定義的 filters, servlets, listeners
- (optional) WEB-INF/jetty-web.xml 定義 Jetty IoC config
Setting the Context Path
在 WEB-INF/jetty-web.xml 可設定 context path
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/contextpath</Set> </Configure>
也可以直接在 $JETTY_HOME/webapps/test.xml,就定義了一個 webapp,test.xml 包含 war 的位置,及 contextPath
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test.war</Set> <Set name="contextPath">/test</Set> </Configure>
Setting an Authentication Realm
標準 realm name 設定在 web.xml,例如以下是宣告使用 BASIC authentication,並使用 "Test Realm"
<login-config> <auth-method>BASIC</auth-method> <realm-name>Test Realm</realm-name> </login-config>
"Test Realm" 設定在 $JETTY_BASE/etc/test-realm.xml,並傳入 start.ini 及 start.d/server.ini
以下設定 LoginService
<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-" "http://www.eclipse.org/jetty/configure_9_3.dtd"> <Configure id="Server" class="org.eclipse.jetty.server.Server"> <!-- =========================================================== --> <!-- Configure Authentication Login Service --> <!-- Realms may be configured for the entire server here, or --> <!-- they can be configured for a specific web app in a context --> <!-- configuration (see $(jetty.home)/webapps/test.xml for an --> <!-- example). --> <!-- =========================================================== --> <Call name="addBean"> <Arg> <New class="org.eclipse.jetty.security.HashLoginService"> <Set name="name">Test Realm</Set> <Set name="config"><Property name="jetty.demo.realm" default="etc/realm.properties"/></Set> <Set name="hotReload">false</Set> </New> </Arg> </Call> <Get class="org.eclipse.jetty.util.log.Log" name="rootLogger"> <Call name="warn"><Arg>demo test-realm is deployed. DO NOT USE IN PRODUCTION!</Arg></Call> </Get> </Configure>
隱藏 Server 資訊
在 start.ini 將 server module 裡面的 jetty.httpConfig.sendServerVersion
設定改為 false
--module=server
## Whether to send the Server: header
jetty.httpConfig.sendServerVersion=false
References
Deploying Web Applications in Jetty