介紹
Apache TomEE(音tommy), 多麼熟悉的名字呀!不錯,它是Tomcat的變身,融合JavaEE之特性而成: TomEE = Tomcat + java EE 。那麼,它有何與衆不同之處呢?
衆多應用伺服器使用 Tomcat 提供的 servlet 功能。 這是個不錯的選擇,Tomcat是一款優秀的 servlet 容器。與其它應用伺服器相比, TomEE 不是把 Tomcat 嵌入到應用伺服器中, 而是把 EJB, CDI 及 其它 Java EE特性融入到 Tomcat 中,給你一個以 Tomcat 為主、完全相容的 Web Profile伺服器。建立TomEE 很簡單,隻需将 Tomcat zip 檔案解壓縮,加入自己的 jar 包,并在 conf/server.xml 檔案裡添加一個單執行個體監聽器(single listener),然後重新壓縮打包就可以了。
TomEE 開發有三條很重要的指導性原則:
- 保持小巧
- 基于标準
- 秉承Tomcat衣缽
尤其是第三條,我們是要在 Tomcat 中加入特性,而不是要去除 Tomcat 的特性。
釋出應用和普通 Tomcat 無異,将war包放到 webapps目錄下即可。
也可以用 TomEE 的配置檔案指向你的應用源代碼,
定義在 server.xml 或 context.xml 檔案中的 應用依舊可以工作。
之前難以做到的一些事性,諸如像 WebService 或 EJB 那樣的所有Jave EE 安全概念,
現在都可以安全無縫地工作在 Tomcat 領域(Tomcat Realms)了。
這樣的設計理念并不隻是增強伺服器本身而已,它也帶來了其它好處。
既然,它是 Tomcat 的延伸版本,那麼,能和 Tomcat 一起工作的所有工具,
如 EEclipse WTP 那樣的內建開發工具(IDE tool),也能和 TomEE 和諧工作。
TomEE 的确是真正的 Tomcat 伺服器,并且具備所有 Jave EE Web Profile 的特性,一點不漏。
版本
Apache TomEE 可配置三種不同的版本:Webprofile, JAX-RS, and Plus。Webprofile 提供了最小的釋出版(僅27M),和Java EE Web Profile完全相容; JAX-RS 在 Web Profie 基礎上, 添加了 Apache CXF 的精簡版來實作 JAX-RS 支援,依然基于 Web Profile 标準;Plus 包提供了包含 JMS, JAX-WS 和 JCA 等特性,但它不是基于 Java EE 标準的。
下表列出了三種版本所有不同的特性:
Feature | WebProfile | JAX-RS | Plus |
Servlet 3.0 | Yes | Yes | Yes |
CDI | Yes | Yes | Yes |
EJB | Yes | Yes | Yes |
JPA | Yes | Yes | Yes |
JSF | Yes | Yes | Yes |
JSP | Yes | Yes | Yes |
JSTL | Yes | Yes | Yes |
JTA | Yes | Yes | Yes |
JavaMail | Yes | Yes | Yes |
Bean Validation | Yes | Yes | Yes |
JAX-RS | No | Yes | Yes |
JAX-WS | No | No | Yes |
JMS | No | No | Yes |
Connector | No | No | Yes |
入門
先到Apache TomEE 下載下傳頁面 獲得其中一個釋出版,在寫這篇文章時的最新版是 1.5.0 。 下載下傳解壓後,檢視一下它的檔案目錄結構,你會發現它和 Tocmcat 多麼相似。 bin/ 目錄存放catalina shell/batch 腳本, conf/ 下存放 配置檔案, webapps/ 下 用于存放 war應用釋出包.。 啟動 Tomcat EE 隻要到 bin 目錄 下執行 ./catalin.sh (window 下 執行 catalina.bat)。 啟動一般隻需幾秒,然後在浏覽器位址欄中輸入http://localhost:8080,不出問題, 就能看到自帶的 Tomcat 應用。有一個按鈕可以連結到 TomEE控制台, 可檢視你的設定是否正常工作, 還能檢視 JNDI 配置。
Eclipse 開發環境配置
啟動 Eclipse ,我們來看一個簡單的示例。其它的內建開發工具 如 Netbeans 和 IDEA 配置方法雷同。 Eclipse(含 WTP ) 可配置各種不同的應用伺服器,可以釋出代碼, 在你修改代碼後能自動重新釋出。 配置 TomEE 和 配置 Tomcat 無異。
第一步,在 server 視窗選擇 'New server' 連結 :
第二步,選擇 Apache Tomcat 7, 填上 server 名稱:
下一步設定本機 TomEE 的安裝目錄:
要是你的 Eclipse 配置使用 workspace metadata, 而不是 TomEE 的安裝目錄,把 TomEE conf/ 目錄下的配置檔案拷貝到 workspace 是個不錯的選擇。這樣,伺服器直接從 workspace 的 conf/ 目錄下讀取配置。 WTP插件能自動将 Tomcat 配置拷貝到 workspace, 除了 tomee.xml 及 system.properties.
可選的調整 要拷貝必要的檔案,右擊 Server 項目的 localhost-config 檔案夾, 然後 從 conf/ 目錄下導入:
在 web.xml 中, TomEE 預設不設定JSP開發模式的自動編譯參數,這意味着,即使你儲存更改,JSP也不會編譯更新。打開Servers->Tomcat v7.0 Server -localhost-config 目錄下的 web.xml 檔案,更改 JSP servlet,将 development 值設為 true就可以了。
Listing 1: web.xml - configuring development mode for JSPs
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>development</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
一個簡單的應用
設定好開發模式後,讓我們來示範一個簡單的應用。Apache TomEE 自帶了大量示例,可示範Java EE各種不同特性。目前有100多個。是學習Java EE 新特性極佳的入門資料。在TomEE Subversion 倉庫可以下載下傳到這些例子。此處引用 moviefun 例子。示例代碼見http://tomee.apache.org/examples-trunk/moviefun/README.html。這是個簡單的 web 應用,結合了 Web Profile 的一些特性。 應用定義了一個簡單的 POJO 代表 Movie, 用 JPA 從資料庫存取。代碼如下:
Listing 2: Movie Entity
@Entity
public class Movie implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String director;
private String title;
private int year;
private String genre;
private int rating;
public Movie() {
}
// SNIP getter and setters below...
}
類中使用了anotation 标注了持久化上下文,以便注入簡單的 EJB 或 CDI bean 執行個體,并通過 JPA 在資料庫中存取Movie 對象。
Apache TomEE 支援 EJB 1.0 到 3.1版本。 EJB 3.0 的建立較之前版本容易了很多,3.1 版本作了進一步簡化。其中一個新特性叫"無接口"示圖 ("no-interface" view), 意味着 EJB session bean不必再提供接口。
下列展示了一個簡單的無狀态 session EJB, 用 JPA2 管理資料存取。并标注了 anotation @Stateless (EJB 中所必需的),然後通過 TomEE 使用 @PersistenceContext annotation 注入執行個體。
Listing 3: Stateless session bean using JPA2
@Stateless
public class MoviesBean {
@PersistenceContext(unitName = "movie-unit")
private EntityManager entityManager;
public Movie find(Long id) {
return entityManager.find(Movie.class, id);
}
public void addMovie(Movie movie) {
entityManager.persist(movie);
}
public void deleteMovie(Movie movie) {
entityManager.remove(movie);
}
public void deleteMovieId(long id) {
Movie movie = entityManager.find(Movie.class, id);
deleteMovie(movie);
}
public List<Movie> getMovies() {
CriteriaQuery<Movie> cq = entityManager.getCriteriaBuilder().createQuery(Movie.class);
cq.select(cq.from(Movie.class));
return entityManager.createQuery(cq).getResultList();
}
}
類還提供了簡單的方法,如查找,删除對象等。getMovies() 從資料庫中取出所有的 Movie 執行個體,這裡沒有例行的事務控制。EJB的方法會預設管理事務。TomEE 也已經為你省下功夫。
這個簡單的 bean 提供了與資料庫互動的 API。現在,我們可以用它了! 讓我們來看一下 moviefun's user 接口。web 前端與這個 EJB 互動有很多方法,比如可以用 JSF ManagedBean 調用,或者其它 MVC 架構調用。為簡單起見,本例使用一個 servlet 和這個 EJB 通訊,然後将結果轉給 JSP 頁面。
正如你所料, TomEE 以 Tomcat 7 為核心, 支援 Servlet 3.0 spec。 這允許我們建立一個類,來繼承 javax.servlet.http.HttpServlet ,并标注 anotation @WebServlet。Servlets 和 managed bean 都可以給标注了 @EJB annotation 的字段注入值。 CDI beans 則通過@Inject annotation 。TomEE 同樣支援@Inject 構造注入,該特性已加入到 JaveEE 7 中了。
Listing 4: Servlet with session bean injected
@WebServlet("/moviefun/*")
public class ActionServlet extends HttpServlet {
private static final long serialVersionUID = -5832176047021911038L;
@EJB
private MoviesBean moviesBean;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Movie> range = moviesBean.getMovies();
request.setAttribute("movies", movies);
}
request.getRequestDispatcher("WEB-INF/moviefun.jsp").forward(request, response);
}
}
我們可以用一個簡單的 JSP 來展示資料
Listing 5: JSP to render movies
<div>
<table>
<thead>
<tr>
<th>Title</th>
<th>Director</th>
<th>Genre</th>
<th>Rating</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<c:forEach items="${movies}" var="movie">
<tr>
<td><c:out value="${movie.title}" /></td>
<td><c:out value="${movie.director}" /></td>
<td><c:out value="${movie.genre}" /></td>
<td><c:out value="${movie.rating}" /></td>
<td><c:out value="${movie.year}" /></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
OK,有了上面三個類和一個 JSP ,就可以開始了,另外,得再配置一個檔案,META-INF/persistence.xml, 提供持久單元的基本資訊友善注入EJB。
Listing 6: Persistence.xml
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="movie-unit">
<jta-data-source>movieDatabase</jta-data-source>
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
<class>org.superbiz.moviefun.Movie</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
</properties>
</persistence-unit>
</persistence>
檔案定義了 @Entity 類 org.superbiz.moviefun.Movie ,指定了OpenJPA 自動建立資料庫腳本schema, 要是資料庫不存在對應的表。
部署應用
将此子產品添加到伺服器,啟動伺服器後,可以看到應用成功啟動。URL中應用的位址取決于 .war 包名 或 Eclipse下項目名,假設為 example, 則釋出到 http://localhost:8080/example/
瞧, 不用EARs!
你可以看到所有的東西都在一個子產品裡,被打包成單一的 WAR 檔案,不用EJB 建構 EAR 檔案,這一特性源于 TomEE 。 TomEE 在幾年前就有了,如今為 JavaEE 所吸收。這是 TomEE 給 Java EE 所作的最重要貢獻之一。
所有記憶體都是你的!
值得指出的一點是,TomEE 以預設的記憶體參數運作 - 跑在我的 Mac 64bit server JDK 1.6 上,預設最大是128MB。
TomEE 實際上是基于Amazon EC2 微執行個體标準,其任意一個隻要613MB 的RAM空間--在現在的水準這不算多。但用 TomEE 作為你的應用伺服器,那613Mb 中大部分都可以供你的應用使用。這為你的應用留下了足夠的記憶體空間。我們曾經在一個隻有256MB RAM 的 Raspberry Pi 機器運作 TomEE 和 moviefun 執行個體,TomEE 運作 moviefun 例子隻用了約其中30Mb。那個隻要 35 美元的成本,誰說 Java EE 笨重或花費昂貴來着?
資料庫配置
你可能已經注意到我們使用和部署了一個使用資料庫的應用,然而在 TomEE 中未作任何實際配置。若是在 Eclipse 中重新開機 TomEE 服務, 你可以看到所有的應用資料都已持久化了。那麼資料到底存到了哪裡?資料源又是如何配置的?
TomEE 使用了一個單一的XML配置檔案,conf/目錄下的 tomee.xml 。你可以看到與預設的 EJB pools 、資料源、資源擴充卡等設定有所不同。文法與你所見的其它應用的 XML配置檔案也有差别。它的配置風格是基于Apache httpd 服務,保持盡可能的簡單易讀。比如時間設定,不是指定用毫秒,可以表達成任一時間機關的組合,如"1 hour and 10 minutes and 30 seconds"。
預設的資料源可以如下代碼段添加到 tomee.xml 中。
Listing 7: Configuring a datasource in tomee.xml
<Resource id="movieDatabase" type="DataSource">
JdbcDriver com.mysql.jdbc.Driver
JdbcUrl jdbc:mysql://localhost:3306/moviefun
UserName username
Password password
JtaManaged true
</Resource>
在檔案中指定你資料庫的JdbcDriver,JdbcUrl, UserName 和 Password,同時需要将 JDBC 驅動 jar 添加到 TomEE/lib 目錄。
其中 Resource ID 要比對 persistence.xml 檔案中定義的<jta-data-source> 或<non-jta-data-source> 。 若在 tomee.xml 中沒有找到相比對的資源,則使用預設的資料庫,正像上面的例子,預設的資料庫是一個基于HSQLDB執行個體的檔案,位于 data/ 目錄。該檔案也可以被配置成 JMS 隊列和主題,和其它任一可供應用使用的資源形式。
配置也可以通過系統屬性設定,上例 example 的資料源像下面那樣以 JAVA_OPTS 參數指定:
-DmovieDatabase.JdbcDriver=com.mysql.jdbc.Driver
-DmovieDatabase.JdbcUrl=jdbc:mysql://localhost:3306/moviefun
-DmovieDatabase.UserName=username -DmovieDatabase.Password=password
或者,可以添加到 conf/system.properties 檔案中。更多資訊可以參考 TomEE website 。
安全性
TomEE 完全內建了 Java EE 的安全性,無縫、一緻地運作于 web 層,EJBs 和 webservices 端。添加一個應用和任何一個 定制的Tomcat Realms 的實作都相當簡單, 如 JDBC,LDAP 或 MongoDB 支援的 Realms, 不作任何修改,都可以運作在 TomEE 中。另外,也支援用 JAAS conf/目錄下login.config定制的安全子產品。可以通過以下步驟給 moviefun 示例 添加 基本的 HTTP 安全驗證。 在 tomcat-users.xml 中定義一個 user 和 role:
<user username="movies" password="movies" roles="moviefun"/>
在 web.xml 中添加一些安全配置,如下:
Listing 8: web.xml security configuration
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>UserDatabase</realm-name>
</login-config>
<security-role>
<role-name>moviefun</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>Everything</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>moviefun</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
最後為 MoviesBean 類 添加 @RolesDeclared 和 @RolesAllowed anotation。或者添加在一個你想授權通路的單一方法上。如下
Listing 9: adding roles to session bean
@Stateless
@DeclareRoles(value = { "moviefun" })
public class MoviesBean {
@RolesAllowed(value = { "moviefun" })
public List<Movie> findAll(int firstResult, int maxResults) {
...
}
}
以上配置,通路應用裡的任何頁面,都需提供驗證,使用者名和密碼通過tomcat 的 UserDatabase realm 的 tomcat-users.xml 檢驗。最後, TomEE 将登入規則和相關權限傳遞給 EJB。隻有授權的使用者方可調用 EJB 的方法。遠端用戶端調用 EJB 的方法同樣需要使用者名和密碼校驗。
作者資訊
Jon 是一個開源和Java EE的愛好者,任職于英國 Weatherbys Ltd公司。作為開源的使用者和貢獻者,在過去的四年裡, Jon 送出了 Apache TomEE and OpenEJB 項目, 并緻力于多種不同的特性,包括早期內建 Tomcat 7 到TomEE 中, EJB 3.1 compliance, TomEE Arquillian adapters 和 OpenEJB Eclipse 插件的部分工作. 當為 Apache TomEE 孜孜不倦,夜以繼日地工作的同時, Jon 同樣享受着生活,喜歡烹饪, 愛看Formula One 賽車, 偶爾還打打高爾夫球。
該文章發表于 JAX Magazine:TomEE - 可以這裡下載下傳。
翻譯不當之處,可檢視原文。 或參考 開源中國的另一翻譯版本。
感謝你的關注,願你至少能夠以陪伴電腦一樣長的時間來陪伴你的親人和朋友。願你和你的親朋健康快樂!