TomEE 入门指导
介绍Apache TomEE(音tommy),多么熟悉的名字呀!不错,它是Tomcat的变身,融合JavaEE之特性而成: TomEE = Tomcat+ java EE 。那么,它有何与众不同之处呢?众多应用服务器使用Tomcat 提供的 servlet 功能。 这是个不错的选择,Tomcat是一款优秀的 servlet 容器。与其它应用服务器相
介绍
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 Tomcat 7, 填上 server 名称:
下一步设置本机 TomEE 的安装目录:
要是你的 Eclipse 配置使用 workspace metadata, 而不是 TomEE 的安装目录,把 TomEE conf/ 目录下的配置文件拷贝到 workspace 是个不错的选择。这样,服务器直接从 workspace 的 conf/ 目录下读取配置。 WTP插件能自动将 Tomcat 配置拷贝到 workspace, 除了 tomee.xml 及 system.properties.
在 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 。
安全性
<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 - 可以这里下载。
翻译不当之处,可查看原文。 或参考 开源中国的另一翻译版本。
感谢你的关注,愿你至少能够以陪伴电脑一样长的时间来陪伴你的亲人和朋友。愿你和你的亲朋健康快乐!
更多推荐
所有评论(0)