Apache TomEE 入門指南
Apache TomEE 入門指南
介紹
Apache TomEE(發音同“tommy”)是一個新的JavaEE服務器,由Apache軟件基金會開發,你大概能夠從它的名字猜到,它是從Tomcat而來,同時加入的JavaEE的特征:TomEE=Tomcat+java EE。因此,它與其他的應用服務器有什么不同呢?
有一些應用服務器是使用Tomcat提供的servlet功能,這不是什么壞事——Tomcat是最好的servlet容器。TomEE的方法就有點不同了——作為對直接把Tomcat嵌入到應用服務器的取代,TomEE嵌入了EJB、CDI和其他JavaEE特征到Tomcat里,給你一個完整符合Web Profile的服務器但同時也保留了Tomcat的領導地位。在沒解壓的Tomcat里,加入了自己的jar包、一個對conf/server.xml的單一監聽器,然后壓縮到備份里,通過這樣把TomEE的包創建而成。
有三個使用TomEE開發的指導原則。 他們是:
- 小巧的
- 有保證的
- 是Tomcat的
每一條都對我們很重要,但是“是Tomcat的”部分尤其如此——我們加入特征到Tomcat,同時,重要的是TomEE沒有丟失與Tomcat的一致性。(TomEE下)的部署機制和常見的Tomcat一樣(只需把你的。war文檔放到webapps/folds)。資源工作在同樣的方式下——你可以使用TomEE的配置文件,但是定義在server.xml或者在你應用程序里的context.xml同樣可以配置。一些以前不可能做到的或者是需要很大工作量的東西現在可以做到了,例如讓所有JavaEE的安全概念能像WebService或者EJB的安全無縫地工作在Tomcat Realms上。
這不僅僅是把事情在服務器上做的更好的哲學,還提供了其他的優勢。因為TomEE僅僅是Tomcat的一個擴展版本,任何能在Tomcat上使用的工具,如像Eclipse WTP一樣的IDE工具,全部都能用在TomEE上。
TomEE確實是一個真正的Tomcat服務器,它把所有JavaEE Web Profile特征加到Tomcat上同時沒有去掉任何特性。
模式(flavours)
Apache TomEE有3種不同的工作模式可以使用:Webprofile,JAX-RS和Plus。Webprofile提供了最小的分支版本(僅僅27MB)同時它完全符合JavaEE Web Profile。JAX-RS建立在Web Profile上,用一個修整過的Apache CXF版本加入對JAX-RS的支持,同時也保證對Web Profile的支持。Plus的包提供了TomEE可用的全部特征,包括了JMS、JAX-WS和JCA,但這次不對JavaEE的支持有所保證。
下面的表格展示了3個不同的模式所支持的不同特征。
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。一旦下載完成,將zip文件解壓到你的機器上的某一位置。如果你看看文件夾結構,你可能會馬上注意到TomEE多么像Tomcat規則的一個拷貝。常用的 shell/batch 腳本在bin/目錄下,TomEE配置文件在conf/目錄下,應用程序發布時通過拷貝.war文件到 webapps/目錄下。通過改變到bin/文件夾并運行./catalina.sh文件以啟動TomEE (如果你是用的Windows那么就是catalina.bat文件)。
在一臺常規配置的機器上,TomEE 啟動一般需要幾秒鐘。一旦啟動,打開瀏覽器輸入 http://localhost:8080。如果一切正常啟動,將會顯示出默認的Tomcat應用程序。在該應用程序里有一個鏈接到TomEE控制臺的額外按鈕。TomEE控制臺提供了一些頁面和一個JNDI瀏覽器,在這些頁面上能對你的啟動程序是否正確進行核實。
使用Eclipse來搭建開發環境
讓我們啟動IDE,來演示一個簡單的程序。我們這里的IDE使用Eclipse,其它的IDE,像Netbeans 和Intellij IDEA可以以同樣的方式進行配置。 我有 一個帶有WTP的Java EE Eclipse 包,可以啟動多個不同的服務器,發布你的代碼到服務器上,并且自動重新部署你所做的任何改變。在Eclipse中啟動TomEE和你啟動Tomcat是相同的過程。
首先,在服務器視圖下選擇‘New server’。
然后,選擇 Apache Tomcat 7,將服務器名稱改成你喜歡的名稱:
在向導的下一頁, ‘select the installation directory’選擇你解壓的TomEE安裝包的位置:
可選調整
如果你已經配置Eclipse使用工作區元數據來接管TomEE的安全,一個好的建議是從TomEE包的conf/ 路徑里復制文件到工作區。當運行在這種模式下,配置的文件會從工作區的conf/路徑讀取代替原來TomEE的conf路徑。WTP插件對自動把Tomcat的一些配置文件復制到工作區很有幫助,但不會獲得tomee.xml或者system.properties。
要復制需要的文件到工作區,右鍵點擊在Servers項目下的localhost-config文件夾,然后從conf/路徑導入文件。
默認情況下,在web.xml文件中,TomEE沒有為JSP編譯設置開發者參數,也就意味著即使你保存了對他們的更改,JSP也不會更新。為了改變這一點,打開在項目資源管理器里的 localhost-config 文文件夾,位于Servers->Tomcat v7.0 Server下的web.xml文件 ,更改jsp servlet,將開發者模式設為true,如列表1所示。
列表1:web.xml-為JSP配置開發者模式
<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 里有一些應用例子來展示一些JavaEE里可用的特征。現在大概已經有100個例子了,這些都能開始學習新的JavaEE特征給與服務。這些例子都可以在TomEE SubVersion倉庫里看到。我打算在本文使用moviefun這個例子。完整的源代碼在http://tomee.apache.org/examples-trunk/moviefun/README.html。這個例子只是一個簡單的web應用程序,使用到一些Web Profile里的可用特征。
首先,應用有一個簡單的POJO來代表一個Movie,這使用到JPA來存儲和獲取一個在數據庫里的Movie。列表2顯示了一個帶有標題,導演,流派,年份,排名等屬性的movie的POJO。
列表2: Movie 實體類
@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... }
使用JPA,提供了一個簡單地能持久化到數據庫的對象。為了實現這一點,一個持久化上下文需要注入到一個簡單的EJB或者CDI bean,同時能被用來檢索和持久化Movie對象到數據庫中。
Apache TomEE為EJB提供了從版本 1到版本3.1的支持。EBJ3.0使EJB的創建較之前的版本更加簡單,版本3.1更進一步。其中一個新特性之一是“no-interface”視圖,這意味著EJB session bean 不再需要提供接口。
列表3 列出了一個簡單的無狀態會話EJB,它使用JPA2能夠管理存儲和獲取數據。這個EJB是一個使用了@Stateless來注解的簡單POJO(這就是要使它成為EJB所要做的全部東西),以及它有一個使用@PersistenceContext注解由TomEE注入的實體管理器。
列表3: 使用JPA2的無狀態會話Bean
@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()方法通過構造一個簡單的JPA2查詢來從數據庫中獲取完整的Movie集合。注意這里并沒有引用事務的begin或commit語句。EJB的方法默認是事務型的,所以這里并不需要直接引用。TomEE已經在節約你的時間了。
這個簡單的Bean提供了簡單的API來與數據庫進行交互。現在我們需要一些東西來使用它。所以,讓我們看下moviefun的用戶接口吧。一個web前端有很多方法來與EJB交互——例如它能夠通過一個JSF的ManagedBean來引用火災你能夠通過其他的MVC框架來查閱EJB。為讓它保持簡單,這個例子使用了一個展示在列表4里servlet來和EJB交互,然后轉發結果到一個JSP頁面。
作為你期待已久的,TomEE的核心包含了Tomcat7,它支持Servlet3.0規范。這允許我們創建一個繼承javax.servlet.http.HttpServelt和使用@WebServlet.Servlets注解的類,以及管理Bean能夠用@EJB注解在字段上來把EJB注入到它們的字段里,同時,CDI Bean能夠使用@Inject注解來注入。TomEE同樣支持使用@Inject構造函數對Servlet的注入,這個特征在JavaEE7的時候加入的。
列表4: 使用了會話Bean注入的Servlet
@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來顯示數據,同時在表格中增加一個新條目,如列表5中的片段。
列表5:JSP來呈現電影
<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>
到此,我們僅有三個類和一個JSP,我們準備去執行。還需要一個附加文件,META-INF/persistence.xml,該文件提供一些關于注入到EJB的持久化單元的一些基本信息。
列表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>
在列表6中顯示的persistence.xml文件的例子,表明使用了 @Entity類(在該例子中是(org.superbiz.moviefun.Movie ),同時它不存在的話,指定的 OpenJPA 應該自動在數據庫中為我們建立模式。
部署應用
現在我們可以準備部署應用了。你可以把這個模塊加入到服務器同時啟動服務器。
你應該看到應用成果啟動,也沒什么錯誤。應用的URL會合.war包的文件名一樣(或者是Eclipse的項目名),作為一個例子,example.war部署到 http://localhost:8080/example/.
看吧,不需要用到EAR!
你會注意到所有東西都在一個模塊里,這個模塊就是打包到一個單一的WAR文件里的。這里沒有必要去把EJB分離到一個JAR包來構造一個EAR文件,雖然這是以前JavaEE版本的做法。這實際上是來源于TomEE的一項特征,這花費了TomEE好幾年的時間,同時這也是它對JavaEE的第一個貢獻。
你的所有內存都由你來管控!
值得指出的是TomEE運行在默認的內存參數上——在我的MAC電腦上運行一個64位的JDK1.6服務版,使用了128MB作為默認最大內存,同時TomEE運行僅使用了大概30MB來運行moviefun這個例子。
這留給你的應用程序大量的內存。TomEE實際上在注冊使用的Amazon EC2微實例,每個都有613MB的RAM——對于現今的標準來說不算太多。但使用TomEE作為你的應用服務器,對于你的應用來說是613MB是十分充足了。我們甚至能夠在一個有256MB內存的Raspberry PI(超小型電腦)上運行TomEE和moviefun應用例子,這電腦只需花費$35。誰說JavaEE是笨重和昂貴的?
數據庫配置
你也可能注意到了,我們開發和部署了一個數據庫應用,但無論什么也沒在TomEE上做過配置。如果你在Eclipse里重啟TomEE服務器,你就會注意到應用程序的所有數據已經持久化了。那么數據真正是存放在哪里呢,以及它的數據源是怎么配置的?
TomEE是使用一個XML配置文件來配置的,tomee.xml,這個文件放在conf/ 路徑下。如果你看一下這個文件,你會看到一些使用默認設置的不同東西——EJB池,數據源和資源適配器。這里的語法可能和其他你看到過的應用服務器的XML配置文件有所不同。它是基于Apache httpd服務器的配置風格的,目的是讓人們更容易去閱讀它。時間,例如一個bean池的超時時間,在這里并沒有規定為毫秒,它能夠隨你喜歡使用各種時間單位來組合的,例如“1小時10分30秒”。
能夠通過列表7的方法通過在tomee.xml里加入一段內容來定義一個數據庫。
列表7: 在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來匹配JDBC提供的類,同時設置JdbcUrl,UserName和Password來匹配你的數據庫。你也可能需要部署你想用的JDBC驅動,你可以簡單地把jar包扔到TomEE/lib路徑即可。
Resource ID應該和定義在persistence.xml里的<jta-data-source>或<non-jta-data-source>匹配。如果在tomee.xml文件里找不到匹配的資源,將要發生的是會使用默認的數據庫。默認數據庫是一個基于HSQLDB的文件,它的目錄在data/ 路徑。這個文件也可以用來配置JMS隊列和主題,以及其他你想用在你應用上的資源。
配置設置也能通過系統屬性來指定。數據源例子可以像JAVA_OPS一樣作為系統屬性來配置:
-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在一個與web層、EJB和Web服務無縫和一致的方式下緊密地整合了JavaEE安全。加入一個應用程序或者任何定制的Tomcat Realm實現真的是很簡單,例如JDBC、LDAP或MongoDB支持的Realms在不改變任何東西的情況下仍能在TomEE上工作。作為選擇,也支持通過在conf路徑下的一個JAAS login.config文件定制安全模塊。通過一下步驟能夠把使用基于HTTP認證的安全加入到moviefun例子中:
在tomcat-users.xml文件中加入一個用戶和角色:
<user username="movies" password="movies" roles="moviefun"/>
添加一些如列表8展示的安全配置到 web.xml中。
列表8: web.xml安全配置
<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>
最后加入@RoleDeclared以及@RolesAllowed到MovieBean類中,或者加入到你想授權訪問的單獨方法上,如列表9展示:
列表9:加入角色到會話bean
@Stateless @DeclareRoles(value = { "moviefun" }) public class MoviesBean { @RolesAllowed(value = { "moviefun" }) public List<Movie> findAll(int firstResult, int maxResults) { ... } }
由于有了這個配置,在瀏覽器里訪問這個應用程序的任何頁面都需要通過一個基本的認證對話框來認證。用戶名和密碼的將會檢查Tomcat域里的UserDatabase,它使用tomcat-users.xml文件里配置的參數。最后TomEE會登陸的當事人和關聯的角色傳入EJB。只有用戶有經過允許的角色才能執行在EJB上方法。在遠程客戶端執行EJB上的方法也會要求發送用戶名和密碼,同時將在UserDatabase域中認證。