点击这里给我发消息 点击这里给我发消息

详解EJB 3.0是如何简化应用程序的开发

添加时间:2013-12-7
    相关阅读: 开发 数据库 程序 Oracle 优化

  实体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
  ("s
咨询热线:020-85648757 85648755 85648616 0755-27912581 客服:020-85648756 0755-27912581 业务传真:020-32579052
广州市网景网络科技有限公司 Copyright◎2003-2008 Veelink.com. All Rights Reserved.
广州商务地址:广东省广州市黄埔大道中203号(海景园区)海景花园C栋501室
= 深圳商务地址:深圳市宝源路华丰宝源大厦606
研发中心:广东广州市天河软件园海景园区 粤ICP备05103322号 工商注册