• 1. EJB基本概念 EJB三类构件 EJB组成
  • 2. 1 EJB—J2EE的基石EJB是Java平台上的服务器端构件模型。用于创建可伸缩、跨平台、分布式应用,并且可创建具有动态扩展性的服务器应用。 EJB的核心思想是将商业逻辑与底层的系统逻辑分开 1 开发者只需关心商业逻辑, 2 EJB容器实现目录服务、事务处理、持久性、安全性等底层系统逻辑。
  • 3. EJBEJB中的beans可以分为: 会话bean(维护会话):表示客户同应用之间进行的会话,是一种商业处理过程对象。 实体bean(处理事务):代表商业过程中处理的永久性的数据。 消息驱动Beans(Message-driven Beans):结合了会话bean 和 JMS的消息监听器的特性, 可异步接收JMS 消息。2 EJB构件
  • 4. 用户接口 应用逻辑 域逻辑 持久层 用户接口 用户接口 应用逻辑可用于所有应用程序的业务逻辑用于某一应用程序的业务逻辑EJB将业务逻辑分成应用与域逻辑业务逻辑
  • 5. 运行在服务器端,其数据需要自己管理 客户通过session bean上的方法来同应用的业务逻辑层上的组件进行交互 Session bean是短暂的,且只有在与之关联的会话存在时才存在2.1 会话BEAN(SESSION BEAN)
  • 6. 会话Bean会话Bean代表的是调用它的客户程序所完成的工作,是商务过程对象。 他们执行商务逻辑、商务规则、算法和工作流程,例如一个会话Bean可以完成价格估计、订单输入、视频压缩、银行之间的转账、股票交易、数据库操作、复杂计算等。他们是包含商务逻辑过程的可重用组件。
  • 7. 2.1.1 会话Bean的生命周期客户端会话的长短决定着一个会话Bean使用的长短。在客户端中止连接时清除会话。 会话:浏览器打开期间、Java Applet运行期间、一个独立的应用程序打开期间、另一个Bean使用该Bean。 存活在内存中,随着周围环境的改变或生或死 会话Bean可以对数据库进行操作,但本身不是持久性对象。
  • 8. EJB会话状态:往返通信 会话Beans分无状态和有状态两种。 无状态的会话:不维护与之交互的客户的会话状态。Beans模拟商业逻辑,比如汇率转换、计算商品价格等。 有状态的会话Beans:包含表示客户会话的“会话”状态的实例变量。通常模拟商业过程,它会临时保存客户信息。一个会话Beans的典型例子是网上的购物车 无状态的会话BEAN开销小,比有状态会话更有效率 2.1.2 会话Bean的子类型
  • 9. 2.1.2.1无状态会话Bean 无状态会话bean
  • 10. 2.1.2.2 状态会话Bean的特征对状态会话Bean实现调度池调度: 每个Bean存储一个特定客户的状态 为了节省资源,提升系统的可伸缩性,需要调度 钝化(Passivation):将状态会话Bean从内存中交换出去,状态保存在硬盘等介质上(类似于操作系统的调度) 激活(Activation):利用存储在介质中的状态,生成(新的)Bean实例 何种调度策略,同容器的实现有关 何时钝化完全由容器决定,除了事务处理Bean 大多数容器采用Just in Time策略激活 钝化和激活对无状态会话Bean没有用处
  • 11. 2.1.2.2 状态会话Bean的特征容器在钝化时必须保存: EJB对象的引用 Home对象的引用 EJB上下文的引用 JNDI命名上下文
  • 12. 2.1.2.3 激活/钝化回调方法
  • 13. 激活/钝化回调方法
  • 14. 表示存储在永久性数据存储位置的业务数据,是持久的对象。 与会话bean不同,实体bean不维护客户端状态 实体bean实例映射到存储在关系数据库表中的一行数据 实体bean每一个实例都具有唯一的标识(主键) 更复杂的entity bean可以代表数据库表间关联视图。 实体bean对象的存活时间与它们相关联的数据实体一样长,持续到它们表示的实体实际从永久性存储器中删除时对象 与会话bean不同,实体可由多个客户共享2.2 实体BEAN( Entity Bean)
  • 15. 对象-关系型数据库映射
  • 16. (本页无文本内容)
  • 17. 2.2.1 实体bean的持久性——BMPBean-Managed Persistence(自管理的持久性):由bean的开发者维护bean与数据库间的映射关系,即对数据库访问的调用是直接编写在bean 的方法中 BEAN开发者编写数据库或应用程序的处理逻辑 优点: 开发者有完全的控制 无需复杂的提供商支持 缺点: 编码复杂 在改变时需要重新编码和部署 影响可移植性
  • 18. 2.2.2 实体bean的持久性——CMPContainer-Managed Persistence(容器管理的持久性):由容器维护bean与数据库间的映射关系,即容器负责生成实现持久性的代码 优点: 提供商解决,可能会有更好的缓冲和性能 在部署描述符中进行改变即可 可移植性好 缺点: 对容器提供商的工具依赖性强 可能不易反映复杂的数据关系
  • 19. 2.3 会话Bean与实体Bean关系会话bean 表示一个业务过程 每一客户一个实例 Short-lived:与客户生命同步 暂态的 服务器崩溃后丢失实体bean 表示业务数据 在多个客户间共享实例 Long-lived:与数据库中数据同步 持久的 服务器崩溃后可重构 总是事务性的
  • 20. EJB通常会话bean和实体bean是一起使用的。 会话bean允许保存客户端的状态信息,客户端和会话bean实例间是一一对应的。 实体bean允许保存记录的信息,实体bean实例和记录间则是一一对应的。 一个理想的情况是客户端通过会话bean连接服务器,然后会话bean通过实体bean访问数据库,这使得既可以保存客户端的信息又可以保存数据库记录的信息。   
  • 21. 会话bean经常用于涉及多个实体bean的业务处理和控制逻辑。SessionEntityEntityEntity
  • 22. 用户接口 应用逻辑 域逻辑 持久层 用户接口 用户接口 应用逻辑可用于所有应用程序的业务逻辑用于某一应用程序的业务逻辑EJB将业务逻辑分成应用与域逻辑业务逻辑
  • 23. 2.4 消息BEAN是EJB2.0 对1.1的一个基础性更改,专门设计处理JMS(java message system) Jms中消息收发是异步的 EJB有两种方式使用JMS 1.1 一种BEAN可用的资源,使用JMS API的BEAN是消息生产者;消息发送称为对列的虚拟通道 2.0:消息BEAN,是消息的使用者,监听特定的虚拟通道,并处理发送给该通道的消息
  • 24. 消息BEAN的特点与其他BEAN区别 不能由客户直接调用,由容器异步调用 没有远程或本地接口 类似于无状态的会话BEAN
  • 25. 3 EJB组成EJB 结构与原理 EJB容器及业务接口 业务逻辑 BEAN元数据
  • 26. EJB的组成
  • 27. 3.1.1 EJB结构模型客户服务器 EJB Beans事务、命名、持久性、安全等服务容器工 厂 接 口远 程 接 口工厂对象桩 (home stub)EJB对象桩 (remote stub)(工厂)Home对象EJB对象(工厂) Home接口(远程) Remote接口JNDI
  • 28. 客户Home RMI StubHome RMI SkeletonBean RMI StubBean RMI SkeletonEJB Home ImplementationEJB ObjectBean1 名为EJBObject的服务器端对象(远程接口的实现)截取方法调用,作为BEAN的服务器端代理,将方法调用传至BEAN本身 2 EJB采用RMI-IIOP进行远程交互,保留了RMI的语法,但传输机制为CORBA的基于Internet的ORB间协议(IIOP)1
  • 29. 3.1.2 EJB 原理图
  • 30. EJBs in PracticeEJBObject
  • 31. RMI机制3
  • 32. 调用EJB
  • 33. EJB容器EJB容器是EJB构件运行的环境,是一层代替bean执行相应服务的接口。 EJB容器负责提供 协调管理 资源管理 版本控制 动态性 一致性 安全 事务处理 RMI等功能  3.2 EJB容器
  • 34. EJB会话和实体bean提供接口,消息bean不提供 Home接口 Home接口定义一组方法来创建新的EJB对象,查找、定位和清除已有的EJB对象。 Remote接口 EJB对象的Remote接口定义EJB构件中提供的可供用户调用的方法,也就是通常所说的实现商业逻辑的函数或过程(如计算商品价格的函数),以供远程客户端调用。    3.2.1 EJB容器的两类接口
  • 35. 用于管理企业bean的各自工具方法客户或 web层组件Home接口 定义用于查找和 实例化bean的工具方法接口 由bean实现的特定方法EJB1231 查找HOME接口 2 通过home接口来创建bean的实例 3通过bean接口来调用bean的方法EjbObject
  • 36. 客户Home接口 Create() Create(A) Create(A,B,C) Create(X,Y,Z)EJB ejbCreate() ejbCreate(A) ejbCreate(A,B,C) ejbCreate(X,Y,Z) Business() Getname()本质上,home接口的creat方法是bean的构造函数:当客户调用create方法时,容器对此bean进行实例化,并将此调用映射到该bean实例包含的相应的ejbCreate方法EJBObject接口 business() Getname()
  • 37. 3.2.1.1 Home接口指明了生成和清除EJB对象的方法 由Home对象实现,由容器工具实现 Create和Remove由容器调用
  • 38. Home接口作用 定义一组方法来创建新的EJB对象,查找、定位和清除已有的EJB对象。 在EJB构件部署时容器会自动生成相应的Home对象,该对象负责 查找和创建EJB对象 返回EJB对象的引用给客户 用户利用该引用调用EJB构件的方法,得到结果 最后Home对象清除EJB对象。
  • 39. 客户端获取EJB的方法Create()方法:EJB home接口包含一个或多个创建EJB实例的create方法 findXXX()方法:与实体bean进行交互时,使用一个或多个findXXX方法查找现有的ejb
  • 40. 3.2.1.2 EJB对象接口(EJBObject)作用:客户端和Bean实例之间的具有网络功能的中介,处理与中间件相关的事宜。客户端的调用方法都通过EJB对象传递给Enterprise Bean实例。 实现EjbObject接口,由容器调用 声明所有需要远程调用的EJB方法 本地(local)接口是一种高性能版本
  • 41. 3.2.2 不同视图远程 本地
  • 42. 3.2.2.1 远程客户的远程视图远程视图是通过使用远程home接口和远程组件接口来定义的。 计算开销和时间消耗较高 所有远程home接口必须继承EJBHome接口,EJBHome接口进而继承java.rmi.Remote接口,并包含至少一个返回bean对象实例的create方法 远程组件接口继承自EJBObject
  • 43. 可能在不同的系统 和/或JVM上执行 的web组件,J2EE 应用或EJBHome接口 定义EJB共有 的工具方法, 如create(),remove()远程接口 定义可以在 EJB中调用的方法EJB远程客户JVMJVM
  • 44. 3.2.2.2 本地客户的本地视图(local)是通过本地home接口加上该bean的本地接口实现 用于:客户与bean共处一块且在同一jvm中执行时 调用是按引用传递的 Local home接口扩展java.ejb.EJBLocalHome Bean接口扩展javax.ejb.EJBLocalObject
  • 45. Home接口 定义EJB共有 的工具方法, 如findbyXX(),remove()本地接口 定义可以在 EJB中调用的方法EJB本地客户JVM 应用逻辑 域逻辑 用户接口 持久层
  • 46. 3.3 业务逻辑EJB的业务逻辑存在于BEAN类中,包括 业务逻辑本身,包括远程接口定义的方法的实现 一套允许容器管理BEAN生命周期的方法 EJB环境的目的使得开发者将大多数时间用于编写业务逻辑而不是网络和数据库“管道” 各种类型的EJB都有略有不同的生命周期,但公共部分如下 BEAN的创建 BEAN的销毁和删除 BEAN的内部状态的保持和恢复 生命周期方法通常使用ejb开头,这样便于区别业务方法
  • 47. 客户Home RMI StubHome RMI SkeletonBean RMI StubBean RMI SkeletonEJB Home ImplementationEJB ObjectBean名为EJBObject的服务器端对象(远程接口的实现)截取方法调用,作为BEAN的服务器端代理,将方法调用传至BEAN本身
  • 48. 3.4 BEAN元数据作用:为EJB提供配置信息,为EJB的需求和结构提供一种与容器通信的方式 包括 用于查询EJB的EJB标识符或名子 BEAN类型 EJB的远程接口 EJB的本地接口 BEAN EJB需要的外部资源信息,例如数据库连接 所有重要信息打包在一个与EJB类一起的部署描述符中
  • 49. Agency AgencyBean AgencyBean agency.AgencyHome agency.Agency agency.AgencyBean Stateless Container AgencyName java.lang.String J2EE in 21 Days Job Agency jdbc/Agency javax.sql.DataSource Container Shareable
  • 50. 4 实现步骤 客户端
  • 51. 一个EJB的三个关键构件作为Bean的开发者,主要关注于三个构件: EJBHome 接口(扩展javax.ejb.EJBHome接口):定义了创建、查找EJB的方法。 EJBObject接口(扩展javax.ejb.EJBObject接口):定义了在bean中实现的业务逻辑方法。 Bean实现类(实现javax.ejb.EntityBean/SessionBean): 实现业务逻辑。
  • 52. 4.1 EJB构件的实现步骤创建远程接口 创建Home接口 创建Bean的实现类 编译远程接口、Home接口、bean实现类 创建部署描述符 将以上三个文件与部署描述符文件打包为一个ejb-jar文件 部署EJB构件
  • 53. 4.2 运行客户端(EJB的使用)发现EJB 检索,使用EJB:调用远程对象的方法 除去EJB: Agency = null; Remove()
  • 54. 4.2.1发现EJB可通过JNDI访问命名服务(用于存储到EJB本地接口的引用) EJB容器已使用部署中的JNDI名子注册了本地接口,即客户端用于查找本地接口的名字private String agencyJNDI = "java:comp/env/ejb/Agency“; InitialContext ic = new InitialContext(); Object lookup = ic.lookup(agencyJNDI); AgencyHome home = (AgencyHome)PortableRemoteObject.narrow(lookup, AgencyHome.class);
  • 55. EJB的编程
  • 56. 例一实例:一个销售员工的简单账户,Entity Bean的状态存储在account表中,表的结构如下: TABLE account( userId varchar(5) primary key, status varchar(10), info varchar(10) );
  • 57. EJB的实现(举例)—创建远程接口// business methods public interface Account extends EJBObject { //return the account information corresponding to this account. public AccountModel getDetails() throws RemoteException; // updates the contact information for the specified account public void changeContactInformation(ContactInformation info) throws RemoteException; }
  • 58. EJB的实现—创建Home接口public interface AccountHome extends javax.ejb.EJBHome { public Account create(String userId, String status, ContactInformation info) throws RemoteException,DuplicateKeyException,CreateException; public Account findByPrimaryKey (String userId) throws RemoteException, FinderException; }
  • 59. EJB的实现—AccountBean的实现public class AccountBean implements EntityBean { // entity state private String userId; private String status; private String info; // resources private EntityContext context; // implement account interface business methods public void changeContactInformation(String info) { this.info = info; } public AccountModel getDetails() { return(new AccountModel(userId, status, info)); }与EJBObject的方法对应
  • 60. EJB的实现—AccountBean的实现(2)// must match signatures of create methods in Home interface public String ejbCreate (String userId, String status, String info) throws DuplicateKeyException,CreateException { // set the instance data this.userId = userId; this.status = status; this.info = info; }与HOME的方法对应
  • 61. EJB的实现—AccountBean的实现(3)
  • 62. 客户端 Context context = new InitialContext(); Object ref = context.lookup(" Sales_AccountHome "); AccountHome home = (AccountHome ) javax.rmi.PortableRemoteObject.narrow(ref,AccountHome.class); Account account = home.create( “111”,”manager”,”phone:8881234”); account=NULL; ……… account = home. findByPrimaryKey ( “111”); //另外一种方法 AccountModel accountModel=account. getDetails();  
  • 63. 例二AgencyBean(Remote) JobBean SkillBean LocationBean ApplicantBean CustomBean LocalLocal
  • 64. 接口开发 Remote Local 实体bean Cmp Bmp
  • 65. Remote
  • 66. AgencyHome.java(Home接口)package agency; import java.rmi.*; import javax.ejb.*; public interface AgencyHome extends EJBHome { Agency create () throws RemoteException, CreateException; }
  • 67. Agency.java(EJBObject)package agency; import java.rmi.*; import java.util.*; import javax.ejb.*; public interface Agency extends EJBObject { String getAgencyName() throws RemoteException; Collection findAllApplicants() throws RemoteException; void createApplicant(String login, String name, String email) throws RemoteException, DuplicateException, CreateException; void deleteApplicant (String login) throws RemoteException, NotFoundException; Collection findAllCustomers() throws RemoteException; void createCustomer(String login, String name, String email) throws RemoteException, DuplicateException, CreateException; void deleteCustomer (String login) throws RemoteException, NotFoundException; 关于Customer的业务方法
  • 68. Collection getLocations() throws RemoteException; String getLocationDescription(String name) throws RemoteException, NotFoundException; void addLocation(String name, String description) throws RemoteException, DuplicateException; void updateLocation(String name, String description) throws RemoteException, NotFoundException; void removeLocation(String code) throws RemoteException, NotFoundException; Collection getSkills() throws RemoteException; String getSkillDescription(String name) throws RemoteException, NotFoundException; void addSkill(String name, String description) throws RemoteException, DuplicateException; void updateSkill(String name, String description) throws RemoteException, NotFoundException; void removeSkill(String name) throws RemoteException, NotFoundException; List select(String table) throws RemoteException; }
  • 69. package agency; import java.rmi.*; import java.sql.*; import java.util.*; import javax.ejb.*; import javax.naming.* ; import javax.sql.*; import data.*; public class AgencyBean implements SessionBean { private DataSource dataSource; private ApplicantLocalHome applicantHome; private CustomerLocalHome customerHome; private JobLocalHome jobHome; private LocationLocalHome locationHome; private SkillLocalHome skillHome; private String agencyName = ""; public String getAgencyName() { return agencyName; }AgencyBean.java(Bean)Local方式的使用
  • 70. public Collection findAllApplicants() {} public void createApplicant(String login, String name, String email) throws DuplicateException, CreateException{} public void deleteApplicant (String login) throws NotFoundException{ } …… public String getLocationDescription(String name) throws NotFoundException { try { LocationLocal location = locationHome.findByPrimaryKey(name); return location.getDescription(); } catch (FinderException e) { error("Error finding Location description for "+name,e); } return null; } Local方式的使用
  • 71. public void ejbCreate () throws CreateException { } public void ejbActivate(){ } public void ejbPassivate(){ } public void ejbRemove(){ dataSource = null; } private SessionContext ctx; public void setSessionContext(SessionContext ctx) {//完成本地实体bean的home接口的查找 this.ctx = ctx; InitialContext ic = null; try { ic = new InitialContext(); dataSource =(DataSource)ic.lookup("java:comp/env/jdbc/Agency"); agencyName = (String)ic.lookup("java:comp/env/AgencyName"); applicantHome = (ApplicantLocalHome)ic.lookup("java:comp/env/ejb/ApplicantLocal"); customerHome = (CustomerLocalHome)ic.lookup("java:comp/env/ejb/CustomerLocal"); jobHome = (JobLocalHome)ic.lookup("java:comp/env/ejb/JobLocal"); locationHome = (LocationLocalHome)ic.lookup("java:comp/env/ejb/LocationLocal"); skillHome = (SkillLocalHome)ic.lookup("java:comp/env/ejb/SkillLocal"); } catch (NamingException ex) { error("Error looking up depended EJB or resource",ex); return; } } }与Home接口方法create对应本地home接口的查找,JNDI的使用
  • 72. Local
  • 73. 本地接口的使用使用bean可实现位置的透明性,对会话bean有用,但对实体bean用处不大,有时不利影响 客户端有时处理多个实体bean,若都是远程则会导致网络阻塞 本地接口适用于实体bean,也可用于会话bean
  • 74. 实体BEAN编程实体bean与会话bean差别 实体bean继承EntityBean接口 每个实体bean实例都是唯一的,且可通过其主键进行标识 每个实体bean的home接口必须至少有一个finder (findByPrimaryKey)方法,此方法使其他组件能基于其主键来发现实体bean Bean实现的每一个ejbCreate方法必须返回此bean的主键(类) 使用ejbLoad方法和ejbStore方法来将其状态与它们所表示的底层数据库实体同步
  • 75. 实体Bean的创建和删除
  • 76. 实体Bean的创建和删除
  • 77. LocationLocalHome.javapackage data; import java.rmi.*; import java.util.*; import javax.ejb.*; public interface LocationLocalHome extends EJBLocalHome { LocationLocal create (String name, String description) throws CreateException; LocationLocal findByPrimaryKey(String name) throws FinderException; Collection findAll() throws FinderException; }
  • 78. LocationLocal.javapackage data; import java.rmi.*; import javax.ejb.*; public interface LocationLocal extends EJBLocalObject { String getName (); String getDescription (); void setDescription (String description); }
  • 79. LocationBean.javapackage data; import java.rmi.*; import java.sql.*; import java.util.*; import javax.ejb.*; import javax.naming.*; import javax.sql.*; public class LocationBean implements EntityBean { private DataSource dataSource; private String name; private String description; public String getName () { return name; } public String getDescription () { return description; } public void setDescription (String description) { this.description = description;
  • 80. // EJB methods start here public void ejbPostCreate (String name, String description) { } public String ejbCreate (String name, String description) throws CreateException{ } // 以下在BMP中使用 public String ejbFindByPrimaryKey(String name) throws FinderException { } public Collection ejbFindAll() throws FinderException { } / ****************/ public void ejbLoad(){ } public void ejbStore(){ } public void ejbPassivate(){ } public void ejbRemove(){ } private EntityContext ctx; public void setEntityContext(EntityContext ctx){ }//获取JDBC数据源引用 private void closeConnection (Connection con, PreparedStatement stmt, ResultSet rslt){ } private void error (String msg, Exception ex) { }
  • 81. finder方法定位实体返回类型是实体bean的本地接口类型,或是实现该实体bean的本地接口的对象集合public interface EmployeeHome extends javax.ejb.EJBLocalHome{ ... public Employee findByLastName(String name) throws FinderException,EmployeeNotFoundException; public Employee findById(int id) throws FinderException,EmployeeNotFoundException; public Collection findAllEmployees() throws FinderException; public Employee findByPrimarykey(String pk) throws FinderException; ... }
  • 82. EmployeeHome employeeHome = ... Employee workerBee = employeeHome.findByLastName(“Smith”); //调用public abstract EmployeeEJB implements javax.ejb.EntityBean{//bean的实现 public Employee ejbFndByLastName(String last) //与home接口的findbylastName对应 throws FinderException,EmployeeNotFoundException{ Employee theEmployee; try { theEmployee = selectByLastName(last); }catch(Exception e){ throw new EJBException("ejbFindByLastName"+e.getMessage()); } if (theEmployee){ != null{ return theEmployee; }else{ throw new EmployeeNotFoundException("Employee"+last+"not found"); } } }
  • 83. BMP与CMPBMP下,bean提供者编写适当的查找方法与持久性数据存储集进行交互 CMP下,由容器完成此项工作,因此不需要在bean中实现查找方法
  • 84. BEAN管理的持久性用于:当需要进行细粒度的控制时 增加了复杂性
  • 85. LocationLocalHome.javapackage data; import java.rmi.*; import java.util.*; import javax.ejb.*; public interface LocationLocalHome extends EJBLocalHome { LocationLocal create (String name, String description) throws CreateException; LocationLocal findByPrimaryKey(String name) throws FinderException; Collection findAll() throws FinderException; }
  • 86. LocationLocal.javapackage data; import java.rmi.*; import javax.ejb.*; public interface LocationLocal extends EJBLocalObject { String getName (); String getDescription (); void setDescription (String description); }
  • 87. LocationBean.javapackage data; import java.rmi.*; import java.sql.*; import java.util.*; import javax.ejb.*; import javax.naming.*; import javax.sql.*; public class LocationBean implements EntityBean { private DataSource dataSource; private String name; private String description; public String getName () { return name; } public String getDescription () {return description; } public void setDescription (String description) { this.description = description; }
  • 88. // EJB methods start here public void ejbPostCreate (String name, String description) {} public String ejbCreate (String name, String description) throws CreateException { try { ejbFindByPrimaryKey(name); throw new CreateException("Duplicate location name: "+name); } catch (FinderException ex) {} Connection con = null; PreparedStatement stmt = null; try { con = dataSource.getConnection(); stmt = con.prepareStatement( "INSERT INTO Location (name,description) VALUES (?,?)"); stmt.setString(1, name); stmt.setString(2, description); stmt.executeUpdate(); } catch (SQLException e) {error("Error creating Location "+name,e);} finally {closeConnection(con, stmt, null); } this.name = name; this.description = description; return name; }
  • 89. public String ejbFindByPrimaryKey(String name) throws FinderException { Connection con = null; PreparedStatement stmt = null; ResultSet rs = null; try { con = dataSource.getConnection(); stmt = con.prepareStatement( "SELECT name FROM Location WHERE name = ?"); stmt.setString(1, name); rs = stmt.executeQuery(); if (!rs.next()) { throw new ObjectNotFoundException("Unknown location: "+name); } return name; } catch (SQLException e) { error("Error in findByPrimaryKey for "+name,e); } finally { closeConnection(con, stmt, rs); } return null; }
  • 90. public Collection ejbFindAll() throws FinderException { Connection con = null; PreparedStatement stmt = null; ResultSet rs = null; try { con = dataSource.getConnection(); stmt = con.prepareStatement( "SELECT name FROM Location ORDER BY name"); rs = stmt.executeQuery(); Collection col = new ArrayList(); while (rs.next()) { col.add(rs.getString(1)); } return col; } catch (SQLException e) { error("Error in findAll",e); } finally { closeConnection(con, stmt, rs); } return null; }
  • 91. public void ejbLoad(){ name = (String)ctx.getPrimaryKey(); Connection con = null; PreparedStatement stmt = null; ResultSet rs = null; try { con = dataSource.getConnection(); stmt = con.prepareStatement( "SELECT name,description FROM Location WHERE name = ?"); stmt.setString(1, name); rs = stmt.executeQuery(); if (!rs.next()) { error("No data found in ejbLoad for "+name,null); } this.name = rs.getString(1); this.description = rs.getString(2); } catch (SQLException e) { error("Error in ejbLoad for "+name,e); } finally { closeConnection(con, stmt, rs); } }
  • 92. public void ejbStore(){ Connection con = null; PreparedStatement stmt = null; try { con = dataSource.getConnection(); stmt = con.prepareStatement( "UPDATE Location SET description = ? WHERE name = ?"); stmt.setString(1, description); stmt.setString(2, name); stmt.executeUpdate(); } catch (SQLException e) { error("Error in ejbStore for "+name,e); } finally { closeConnection(con, stmt, null); } }
  • 93. public void ejbRemove(){ name = (String)ctx.getPrimaryKey(); Connection con = null; PreparedStatement stmt = null; try { con = dataSource.getConnection(); stmt = con.prepareStatement( "DELETE FROM Location WHERE name = ?"); stmt.setString(1, name); stmt.executeUpdate(); } catch (SQLException e) { error("Error removing location "+name,e); } finally { closeConnection(con, stmt, null); } name = null; description = null; }
  • 94. private EntityContext ctx; public void setEntityContext(EntityContext ctx) { this.ctx = ctx; InitialContext ic = null; try { ic = new InitialContext(); dataSource = (DataSource)ic.lookup("java:comp/env/jdbc/Agency"); } catch (NamingException ex) { error("Error looking up depended EJB or resource",ex); return; } } public void unsetEntityContext() { this.ctx = null; dataSource = null; }
  • 95. private void closeConnection (Connection con, PreparedStatement stmt, ResultSet rslt) { if (rslt != null) { try { rslt.close(); } catch (SQLException e) {} } if (stmt != null) { try { stmt.close(); } catch (SQLException e) {} } if (con != null) { try { con.close(); } catch (SQLException e) {} } }
  • 96. 容器管理的持久性CMP将与实体bean相关联的所有数据库访问委托给容器 Bean开发者不必为建立数据库连接调用而烦恼,也不必编写任何SQL代码来访问数据库中的数据 BEAN依赖于它们的容器根据在该BEAN的部署描述文件中提供的信息来在部署时自动定界事务
  • 97. CMP实体Bean拥有查询语言EJB Query Language (EJB-QL)
  • 98. package data; import java.rmi.*; import java.util.*; import javax.ejb.*; public interface LocationLocalHome extends EJBLocalHome { LocationLocal create (String name, String description) throws CreateException; LocationLocal findByPrimaryKey(String name) throws FinderException; Collection findAll() throws FinderException; }LocationLocalHome.java
  • 99. package data; import java.rmi.*; import javax.ejb.*; public interface LocationLocal extends EJBLocalObject { String getName (); String getDescription (); void setDescription (String description); } LocationLocal.java
  • 100. LocationBean.javapackage data; import java.rmi.*; import java.sql.*; import java.util.*; import javax.ejb.*; import javax.naming.*; import javax.sql.*; public abstract class LocationBean implements EntityBean { public abstract void setName(String name); public abstract Collection getApplicants(); public abstract void setApplicants(Collection applicants); public abstract Collection getJobs(); public abstract void setJobs(Collection jobs); public abstract String getName (); public abstract String getDescription (); public abstract void setDescription (String description);
  • 101. // EJB methods start here public void ejbPostCreate (String name, String description) {} public String ejbCreate (String name, String description) throws CreateException { /* // for BMP, there was a workaround here, namely to call ejbFindByPrimaryKey // under CMP, cannot call since doesn't exist. // could look up own home interface ... but instead, // will rely on unique primary key on RDBMS table try { ((LocationLocalHome)ctx.getEJBHome()).findByPrimaryKey(name); throw new CreateException("Duplicate location name: "+name); } catch (FinderException ex) {} */ setName(name); setDescription(description); return name; }
  • 102. public void ejbLoad(){ } public void ejbStore(){ } public void ejbPassivate(){ setName(null); setDescription(null); } public void ejbActivate(){ } public void ejbRemove(){ } private EntityContext ctx; public void setEntityContext(EntityContext ctx) { this.ctx = ctx; } public void unsetEntityContext() { this.ctx = null; } private void error (String msg, Exception ex) { String s = "LocationBean: "+msg + "\n" + ex; System.out.println(s); throw new EJBException(s,ex); } }
  • 103. LocationBean LocationBean data.LocationLocalHome data.LocationLocal data.LocationBean Container java.lang.String False 2.x Location no description name 配置文件CMP实体bean实现的相当一部分只是简单完成部署描述符
  • 104. no description description name findAll SELECT OBJECT(o) FROM Location o
  • 105. 客户端private String agencyJNDI = "java:comp/env/ejb/Agency“; private Agency getAgency(String agencyJNDI) throws NamingException, RemoteException, CreateException, ClassCastException { InitialContext ic = new InitialContext(); Object lookup = ic.lookup(agencyJNDI); AgencyHome home = (AgencyHome)PortableRemoteObject.narrow(lookup, AgencyHome.class); return home.create(); }
  • 106. private void loadTables(Agency agency) throws RemoteException { customers = new JList(agency.findAllCustomers().toArray()); applicants = new JList(agency.findAllApplicants().toArray()); locations.clear(); Iterator it = agency.getLocations().iterator(); while (it.hasNext()) locations.addElement(it.next()); skills.clear(); it = agency.getSkills().iterator(); while (it.hasNext()) skills.addElement(it.next());
  • 107. 部署描述设置值Remote接口类名Enterprise Bean类名Home接口类名xxxxxx. Account xxxxxx. AccountHome xxxxxx. AccountBean …………..………… Bean名AccountEJBJNDI名Sales_AccountHome
  • 108. 开发角色
  • 109. 开发角色应用程序组件提供者构造应用程序组件应用程序装配者建立应用 部署者部署系统系统管理员服务器/容器提供者提供服务器/容器
  • 110. J2EE产品提供者 J2EE产品提供者是设计并提供实现J2EE规范所定义的J2EE平台、API和其它功能的公司。 这一般是指操作系统、数据库系统、应用程序服务器或Web服务器的卖主,它们依照J2EE的规范实现J2EE平台。
  • 111. 应用程序组件提供者 应用程序组件提供者是指建立J2EE应用程序所使用的Web组件、enterprise bean、applet或应用程序客户端的公司或个人。
  • 112. Enterprise Bean开发者 一个enterprise bean开发者执行下面的任务并递交一个包含enterprise bean的EJB JAR文件:   1、编写并编译源代码   2、详细说明部署描述   3、将.class文件和部署描述绑定到一个EJB JAR文件中
  • 113. Web组件开发者 一个Web组件开发者执行下面的任务并提交一个包含Web组的WAR文件:   1、编写并编译servlet源代码   2、编写JSP和HTML文件   3、详细说明Web组件的部署描述   4、将.class、.jsp、.html和部署描述绑定到WAR文件中
  • 114. J2EE应用程序客户端开发者 一个应用程序客户端开发者执行下面的任务并提交一个包含J2EE应用程序客户端的JAR文件:   1、编写并编译源代码   2、详细说明客户端的部署描述   3、将.class文件和部署描述绑定到JAR文件中
  • 115. 应用程序装配者 应用程序装配者是从组件提供者接受应用程序组件JAR文件并将其装配到一个J2EE应用程序EAR文件中的公司或个人。一个装配者执行下列任务并递交一个包含J2EE应用程序的EAR文件:   1、将上一阶段建立的EJB JAR文件和WAR文件装配到一个J2EE应用程序(EAR)文件中。   2、完成有关J2EE应用程序的部署详细说明。   3、检验EAR文件中的组件是否遵守J2EE规范。
  • 116. 应用程序部署者应用程序部署者可以是公司或个人。 在配置时,部署者按照由应用程序组件提供者提供的指示以解决外部的支持、指定安全设置并定义事务属性。 在安装时,部署者将应用程序组件装入服务器中并生成特定容器的类和接口。
  • 117. 应用程序部署者一个部署者执行下列任务以安装和配置一个J2EE应用程序:   1、将上一阶段生成的J2EE应用程序(EAR)文件添加到J2EE服务器中   2、根据运行环境通过修改J2EE应用程序的部署说明对J2EE应用程序进行配置。   3、检验EAR文件的内容是否遵守J2EE规范   4、部署(安装)J2EE应用程序EAR文件到J2EE服务器中
  • 118. 系统管理员 系统管理员可以是公司或个人。管理企业计算机和网络这些低层结构,并对运行环境进行监控。当应用服务器不正常运行时采取相应的措施。
  • 119. EJB-JAR DDWAR DDJAR DDRAR DD应用程序DD容器DDEJB模块WEB模块客户模块资源模块EAR资源归档的连接器客户端组件DD:部署描述符企业应用程序归档
  • 120. EJB与javaBeans关系 JAVABEANEJB可视化可视化或非可视化无用户界面客户端客户端构件服务器端,可与客户端通信用于C/S结构不一定是C/S一部分
  • 121. EJB与CORBA关系以后会有更多基于CORBA/IIOP的EJB产品出现 为保证基于CORBA/IIOP的EJB产品的互操作性,规范定义了EJB到CROBA的映射 分布映射:EJB与CORBA对象之间的关系,以及JAVA RMI远程接口到OMG IDL的映射 命名映射:如何利用COS命名服务来确定EJB对象 事务映射:EJB的事务支持到OMG OTS的映射 安全性映射:EJB到CORBA的映射
  • 122. 附录
  • 123. 关于JNDI—— Java Name and Directory Interface是为JAVA程序中命名和目录服务定义接口的Java API 只是一个API而不是一个命名和目录服务 下图展示了java程序和底层命名服务之间的JNDI层接口 可通过JNDI服务提供者接口向JNDI层插入其他的命名服务Java程序JNDI应用程序接口(API)命名管理器JNDI服务提供者接口(SPI)LDAPDNSNDSCORBARMINIS
  • 124. 常见命名服务DNS NDS(Novell目录服务)提供网络服务的相关信息 NIS(网络信息服务)提供关于机器,文件,用户,打印机和网络在系统范围内的信息 LDAP(轻量级目录访问协议)是Internet命名服务的一种许可标准;是一种真正的目录服务,支持对象属性和名字;正成为企业目录服务的事实标准 专业化的命名系统:如CORBA,RMI 也支持windows活动目录
  • 125. 获得初始环境 作用:获得一个添加或查找名字的环境 定义:代表整个名称空间的环境 绑定 向环境(命名空间)绑定新的对象:bind() J2EE服务器自动对大多数对象进行绑定 名字查找 需要两类信息:JNDI名字;绑定名字的对象的类 Context.lookup()
  • 126. 环境参数环境为JNDI名字和相关名字的复合名字组提供层次关系 初始环境提供名称空间的顶层视图,子环境则反映分层的复合名字结构 如果需要在同一个复合名字(类似sams/…形式)环境中查找很多名字,最好在子环境中查找简单的名字 samsbook/sams/book的命名空间
  • 127. import javax.naming.*; public class JNDILookupSAMS { public static void main(String[] args) { try { Context ic = new InitialContext(); Context ctx = (Context)ic.lookup("sams"); String name = (String)ctx.lookup("book"); /*可写为:String name = (String)ic.lookup("sams/book");*/ System.out.println(name); } catch (NamingException ex) { System.err.println(ex); System.exit(1); } catch (ClassCastException ex) { System.err.println(ex); System.exit(1); } } }