博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[转载]详解EJB 3.0是如何简化应用程序的开发
阅读量:2451 次
发布时间:2019-05-10

本文共 8507 字,大约阅读时间需要 28 分钟。

详解EJB 3.0是如何简化应用程序的开发
在读过有关EJB 3.0如何简化应用程序开发的文章和邮件后,我决定对EJB 3.0来做一个实验看是否真像所声称的那样。我决定采用J2EE 1.4教程中一个众所周知的演示程序。
我所用RosterA
pp 应用程序有三个实体beans(LeagueBean,TeamBean,PlayerBean),一个会话bean(RosterBean),三个数据 传递对象(LeagueDetails,PlayerDetails,TeamDetails),一个调试工具类和一个客户类。我把这些bean转换、迁 移、或者转变为基于EJB 3.0的应用程序。
迁移该应用程序的步骤如下:
实体beans迁移
数据传递对象(DTOs)迁移
会话beans迁移
客户类迁移
实体bean的迁移
我 从实体bean的迁移(LeagueBean,TeamBean,PlayerBean)着手。不是采用现存的bean并将抽象的方法转换为带有注释(译 者注:这里的注释是单词annotation,后面没有特别说明时都指这个词)的getter和setter方法,而是对RosterApp 的表实施反向工程,这些数据库表来自一个作为EJB 3.0的实体bean的Oracle数据库。结果,我得到三个带有缺省注释集的简单的POJO(League,Player,Team)。有了这些 POJO,剩下的工作只是为Player与Team之间的多对多的关系添加注释。这些注释如下所示:
//Team POJO ManyToMany(cascade=PERSIST,fetch=EAGER) AssociationTable(table=@Table (name="TEAM_PLAYER"), joinColumns=@JoinColumn (name="TEAM_ID", referencedColumnName="ID"), inverseJoinColumns=@JoinColumn (name="PLAYER_ID", referencedColumnName="ID")) public List getPlayers() { return players; } // Player POJO // players is a List in the Team POJO @ManyToMany(mappedBy="players", fetch=EAGER) public List getTeams() { return teams; }
当 所有的O/R映射都迁移成POJO中的注释后,下一项任务就是将带有EJBQL的finder方法从EJB 2.1中迁移到新的POJO中。这些finder方法大多数是为Player bean定义的。EJB 3.0提供NamedQueries注释将单个的NamedQuery对象组合在一起。我采用了现存的应用程序中的所有EJB QL,并生成一个如下所示的NamedQueries 注释。
我没有对原有EJBQL做任何修改,既没有优化,也没有利用EJB3.0标准中提供的EJBQL新特性。
NamedQueries ({
NamedQuery(name="findAll", queryString="SELECT OBJECT(p) FROM Player p"), NamedQuery(name="findByCity", queryString="SELECT DISTINCT OBJECT(p) FROM Player p, in (p.teams) as t where t.city = :city"), NamedQuery(name="findByHigherSalary", queryString="SELECT DISTINCT OBJECT(p1)FROM Player p1, Player p2 WHERE p1.salary > p2.salary AND p2.name = :name "), NamedQuery(name="findByLeague", queryString=" select distinct object(p) from Player p, in (p.teams) as t where t.league = :league"), NamedQuery(name="findByPosition", queryString=" select distinct object(p) from Player p where p.position = :position"), NamedQuery(name="findByPositionAndName", queryString=" select distinct object(p) from Player p where p.position = :position and p.name = :name"), NamedQuery(name="findBySalaryRange", queryString="select distinct object(p) from Player p where p.salary between ?1 and ?2"), NamedQuery(name="findBySport", queryString="select distinct object(p) from Player p, in (p.teams) as t where t.league.sport = ?1"), NamedQuery(name="findByTest", queryString=" select distinct object(p) from Player p where p.name = ?1"), @NamedQuery(name="findNotOnTeam", queryString=" select object(p) from Player p where p.teams is empty") } )
映 射和finder几乎涵盖了实体bean迁移90-95%的工作量。剩余的部分是对Team执行添加与删除操作的ejbSelect语句和方法。这些方法 已经被简化了。下表显示了一个方法迁移前后的代码。EjbSelect方法被作为Session bean中的NamedQuery迁移,详见后述。
// remove operation on Player before //migrationpublic void dropPlayer (Player player){Debug.print ("TeamBean dropPlayer"); try {Collection players = getPlayers();players.remove(player); } catch (Exception ex) {
throw new EJBException(ex.getMessage()); } } //remove operation after migrationpublic void dropPlayer(Player player) {
Debug.print("TeamBean dropPlayer"); getPlayers().remove(player); }
数据传递对象的迁移
RosterApp 的下一个逻辑层是数据传递对象(DTOs)。EJB 3.0中不再需要DTOs,因为实体bean是基于POJO的,只要实现了java.io.Serializable接口,就可以直接在客户层与业务层传 递。现存的Roster 应用程序是使用DTOs在客户层与会话bean之间传递Teams、Player和Leagues数据集合的。
在EJB 3.0持久层规范中,有一个新的EntityManager API,可用于创建、删除、查找和查询实体,使用这个API从持久层上下文中挂接(Attach)和断开(Detach)对象非常简洁。 EntityManager中的合并操作可将被断开实体的状态应用到被EntityManager管理的持久性实体。
基于EJB 3.0的Roster应用程序不要求现成的DTO包,但是我必须确保Team、League和Player POJOs实现java.io.Serializable接口。我还必须去掉像getPlayersofTeamCopy这样的额外方法,这些方法在 EJB 2.1应用程序中做着在DTO和实体bean之间管理数据的烦琐工作。在消除额外的负担后,我必须简化到处使用DTO的会话bean (RosterApp)中的业务方法。示例迁移代码显示在下表中。
//code before migrating to EJB 3.0 public List getTeamsOfLeague (String leagueId) {
Debug.print("RosterBean getTeamsOfLeague"); ArrayList detailsList = new ArrayList(); Collection teams = null; try {
LocalLeague league = leagueHome.findByPrimaryKey(leagueId); teams = league.getTeams(); } catch (Exception ex) {
throw new EJBException(ex.getMessage()); } Iterator i = teams.iterator(); while (i.hasNext()) {
LocalTeam team = (LocalTeam) i.next();TeamDetails details =new TeamDetails(team.getTeamId(), team.getName(), team.getCity()); detailsList.add(details);}return detailsList; } //code after migrating to EJB 3.0 public List getTeamsOfLeague(String leagueId) {
Debug.print("RosterBean getTeamsOfLeague"); League l = (League)getEntityManager().find ("League", leagueId); return l.getTeamList(); }
会话bean的迁移
在 清除DTO后的任务,就是迁移会话bean(RosterBean)。首先,我必须删除home接口和清除remote接口,使之不扩展 EJBObject。然后,bean类和接口必须用@Stateless和@Remote注释进行标注。EJB 2.1中现成的RosterBean(会话bean)有许多与实体bean Team、League和Player交互的方法。移植练习的大部分工作只是通过使用EntityManager API简化业务方法、为ejbSelect方法创建NamedQueries,并使这些方法不与已被删除的DTO交互。
//code using DTOspublic Player getPlayer(String playerId) {
Debug.print("RosterBean getPlayer"); PlayerDetails playerDetails = null; try {LocalPlayer player = playerHome.findByPrimaryKey(playerId); playerDetails =new PlayerDetails(playerId, player.getName(),player.getPosition(), player.getSalary()); } catch (Exception ex) {
throw new EJBException(ex.getMessage()); } return playerDetails; } //code using the new EntityManager //API public Player getPlayer(String playerId) {
Debug.print("RosterBean getPlayer"); return (Player)em.find("Player",playerId); } // code using DTOs and calling //ejbSelect methods in the Entity Beanpublic List getLeaguesOfPlayer(String playerId) {
Debug.print("RosterBean getLeaguesOfPlayer"); ArrayList detailsList = new ArrayList(); Collection leagues = null; try {LocalPlayer player = playerHome.findByPrimaryKey(playerId); leagues = player.getLeagues(); } catch (Exception ex) {
throw new EJBException(ex.getMessage()); } Iterator i = leagues.iterator(); while (i.hasNext()) {
LocalLeague league = (LocalLeague) i.next(); LeagueDetails details =new LeagueDetails(league.getLeagueId(), league.getName(),league.getSport()); detailsList.add(details);}return detailsList; } //Code after migration, no DTOs and //ejbSelect migrated as inline querypublic List getLeaguesOfPlayer(String playerId) {
Debug.print("RosterBean getLeaguesOfPlayer"); Query query = em.createQuery ("select distinct t.league from Player p, in (p.teams) as t where p = ?1"); query.setParameter(0,playerId); return query.getResultList(); }
客户类迁移
一旦完成了会话bean部分的工作,我们就可着手清理客户端代码。主要的不同点是lookup代码,其次,要确保业务方法的返回值直接是POJO而不是DTO,也需要少量的代码修改。
//client code before migrationpublic static void main(String[] args) {
try {
Context initial = new InitialContext(); Object objref = initial.lookup("java:comp/env/ejb/SimpleRoster"); RosterHome home =(RosterHome) PortableRemoteObject.narrow (objref,RosterHome.class); Roster myRoster = home.create(); insertInfo(myRoster); getSomeInfo(myRoster); getMoreInfo(myRoster); System.exit(0); } catch (Exception ex) {
System.err.println("Caught an exception:"); ex.printStackTrace(); } } //client code after migrationpublic static void main(String[] args) {
try {
Context initial = getInitialContext(); Roster myRoster = (Roster)initial.lookup ("java:comp/env/ejb/SimpleRoster"); insertInfo(myRoster);getSomeInfo(myRoster); getMoreInfo(myRoster);System.exit(0); } catch (Exception ex) {
System.err.println("Caught an exception:"); ex.printStackTrace(); } }
现存的EJB 2.1与新的EJB 3.0应用程序另一个大的不同点是描述器文件的数量。现存的应用程序有大量的部署描述器文件而新的应用程序则清除了除application-client.xml和application.xml文件之外的所有描述器文件。
EJB 2.1 EJB 3.0
Number of Java Files 17 7
Number of XML Files (Descriptors) 9 2
我使用一种能算出非注释(译者注:这里指nocommented)行并且非空行的名叫numlines的工具,只有非注释且非空的行被添加到旧的和新的应用程序中。EJB 2.1程序中XML文件的行数统计是根据教程中推荐的部署步骤计算的。
结论:
EJB 3.0的确简化了实体和会话bean的开发工作。使开发变得容易起来的原因是使用了简化的模型、并且采用了广为人知的POJO和接口之类的工件 (Artifacts)。新的EntityManager API是一个大的增强,我可以相当容易地改变业务方法并且不需要去读规格说明书(Spec)。
还有一些其他的优雅特性,比如利用数据 库序列(Database Sequence)的能力,不过为了保持现有EJB 2.1程序与新的EJB 3.0程序之间更多的相似性,我没有做这个变更。当前虽然规范这么说,但还看不到对本地(Native)SQL查询的任何支持。
我更 喜欢利用Native SQL语句的查询而不是EJBQL,因为,数据库的可移植性对我来说不是要优先考虑的因素。尽管EJB规范看来是在朝正确的方向改进,我还是觉得EJB 3.0需要更多的工具支持,以便更多的普通开发人员能够"染指"并在EJB 3.0规范上进行开发。
尽管任何标准的集成开发环境都支持JDK5,是一个不错的开局,我还是认为,应该有更好的工具去支持复杂的映射(如:多对多)、NamedQueries的就地检查和立即反馈,不要等到部署(才发现问题)。
应 用程序的维护是一个不容忽视的问题,因为一个应用程序在开发阶段结束后还有若干年的生命周期。所有使应用程序开发变得简单的特征也将在应用程序的维护阶段 得到回报。总之,我愿意推荐开发者们从一个全新的、不带偏见的视角审视EJB3.0标准,检验一下该标准的新内容,实际使用一下已经公开的那些EJB 3.0容器(在本练习中,我使用的是Oracle EJB 3.0容器)。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-131570/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/374079/viewspace-131570/

你可能感兴趣的文章
pvs-stdio ue4_使用PVS-Studio检查电报开放网络
查看>>
寻找新
查看>>
PostgreSQL中的WAL:2.预写日志
查看>>
zephyr操作系统_检查Zephyr操作系统代码
查看>>
Node.js VS Python:哪个更好?
查看>>
notebooks_.NET Core与Jupyter Notebooks预览1
查看>>
pvs-stdio ue4_华为云:如今PVS-Studio多云
查看>>
vc编程查找计算机运行记录_如何查找计算机的正常运行时间和安装日期
查看>>
steam无法显示成人内容_如何在Steam上查看仅限成人游戏
查看>>
轻松将图像上传到Photobucket
查看>>
如何在iPhone或iPad上启用USB受限模式(适用于iOS 11.4.1)
查看>>
注意:浏览器崩溃的技术支持弹出窗口又回来了
查看>>
如何在Ubuntu 11.10中安装Classic Gnome桌面
查看>>
亚马逊echo中国使用_如何阻止您的Amazon Echo收听
查看>>
linkedin 分享_如何永远阻止LinkedIn的烦人电子邮件
查看>>
ipad和iphone适配_如何在iPhone和iPad上将链接,照片和媒体快速添加到Apple Notes
查看>>
开源星空照片_如何拍摄星空的好照片
查看>>
usb延长线线序_我应该使用哪种延长线?
查看>>
如何使用Google Assistant控制Xbox One
查看>>
图标缓存 vista_在Windows Vista中将Internet Explorer 7图标添加到桌面
查看>>