??xml version="1.0" encoding="utf-8" standalone="yes"?> BMP是在Bean中完成对数据库JDBC的各U调用,也就是说Q在你的实体bean(entity bean)中,明确写入了SQL语句Q如"insert .. "?select ..",q且使用Datasource获得一个数据库资源以及(qing)q接(connection)从而对数据库直接进行增?删除修改?/p>
CMP是由EJB容器自动完成Ҏ(gu)据库的操作,你所有做的,是在实体bean重写入SetXXX或getXXXҎ(gu)Q然后在ejb-jar.xml中定义cmp-field可以?/p>
很明?CMP~写要简单多Q而且数据库操作由EJB容器完成应该是一U趋势,但是CMP有个~点是不够灉|Q如果我们要完成cMSQL搜烦(ch)语句的like命o(h),?select * from A where name like '%banqiao'",CMP无法自动帮助我们完成,q样我们需要BMP自己来写?/p>
在实际应用,一般ؓ(f)了效率考虑Q我们尽量用CMPQ但如何为将来有可能使用BMP作好准备Q就是说有可以g伸到BMP的基。EJB 2.0对CMP的抽象类支持为我们提供了q种实现的基?/p>
M思\是,先用抽象类完成CMP 如果需要BMP 可以extendq个抽象c,然后覆盖原来的方法(用自qҎ(gu)SQL语句操作来覆盖该Ҏ(gu)Q?/p>
以Java 宠物?Java Pet Store Demo 1.3)中的地址实体bean:AddressEJBZ: private EntityContext context = null; // getters and setters for PO CMP fields public abstract String getFirstName(); public Object ejbCreate(String fName, String lName, String s1, public void ejbPostCreate(String fName, String lName, String street1, 在上面的AddressEJB中,我们看到只有setXXX或getXXX的方法?/p>
在相应的部v描述文gejb-jar.xml中我们看? <entity> <cmp-field> 在上面部|文件中Q标明了Address数据库字D? firstName,lastName,street1,street2,city,stateQcountry,zip 一旦我们要使用BMP, 只要l承上面的CMP bean: public class AddressBeanBMP extends AddressEJB { 用我们自qBMPҎ(gu)覆盖AddressEJB中的Ҏ(gu): ejbLoad() -->从数据库中获取数?SELECT) 下面以ejbCreate()Z: public Object ejbCreate(String fName, String lName, String s1, // Insert database record 开?/font> 无论如何׃EJB的复杂性之在J2EE架构中的表现一直不是很好。EJB大概是J2EE架构中唯一一个没有兑现其能够单开发ƈ提高生力的l徏。EJB3.0规范正尝试在q方面作出努力以减轻其开发的复杂性。EJB3.0减轻了开发h员进行底层开发的工作量,它取消或最化了很多(以前q些是必d玎ͼ(j)回调Ҏ(gu)的实玎ͼq且降低了实体Bean?qing)O/R映射模型的复杂性?/font> 在本文中Q我首先?x)介lEJB3.0中几个主要的改变。它对进一步深入了解EJB3.0是非帔R要的。随后,我会(x)从更高的层面来描q已l被提交到EJB3.0规范中的l节Qƈ一个个的讲解新的规范中的改变:(x)实体Bean,O/R映射模型Q实体关pL型和EJB QL(EJB查询语言){等?/font> 背景 EJB3.0中两个重要的变更分别是:(x)使用了Java5中的E序注释工具和基于Hibernate的O/R映射模型?/font> Java5中的元数据工?/font> Java5Q以前叫J2SE1.5或TigerQ中加入了一U新的程序注释工兗通过q个工具你可以自定义注释标记Q通过q些自定义标记来注释字段、方法、类{等。这些注释ƈ不会(x)影响E序的语义,但是可以通过工具Q编译时或运行时Q来解释q些标记q生附加的内容Q比如部|描q文Ӟ(j)Q或者强制某些必ȝq行时行为(比如EJBlg的状态特性)(j)。注释的解析可以通过源文件的解析Q比如编译器或这IDE工具Q或者用Java5中的APIs反射机制。注释只能被定义在源代码层。由于所有被提交到EJB3.0草案中的注释标记都有一个运行时的RetentionPolicyQ因此会(x)增加cL件占用的存储I间Q但q却l容器制造商和工具制造商带来了方ѝ?/font> Hibernate 目前Hibernate非常受欢q,它是开发源代码的Java O/R映射框架Q目的是把开发h员从J琐的数据持久化~程中解脱出来。它也有一个标准的HQLQHibernate 查询语言Q语aQ你可以在新的EJB QL中看到它的媄(jing)子。Hibernate在处理如数据查询、更新、连接池、事务处理、实体关pd理等斚w非常单?/font> 在已l提交的EJB3.0规范中主要涉?qing)两个方面的改变Q?/p>
1. 一套以注释为基的EJB~程模型Q再加上EJB2.1中定义的通过部v描述W和几个接口定义的应用程序行为?/p>
2. 新的实体Bean持久化模型,EJBQL也有许多重要的改变?/p>
q有一些有关上q的提议Q比如:(x)一个新的客L(fng)~程模型Q业务接口的使用以及(qing)实体Bean的生命周期。请注意EJB2.1~程模型Q包括部|描q符和home/remote接口Q仍然是有效的。新的简化模型ƈ没有完全取代EJB2.1模型?/p>
EJB注释 EJB规范l织一个重要的目标是减d始代码的数量Qƈ且他们ؓ(f)此给Z一个完而简介的办法。在EJB3.0的里QQ何类型的企业UBean只是一个加了适当注释的简单Java对象(POJO)。注释可以用于定义bean的业务接口、O/R映射信息、资源引用信息,效果与在EJB2.1中定义部|描q符和接口是一L(fng)。在EJB3.0中部|描q符不再是必ȝ了;home接口也没有了Q你也不必实C务接口(容器可以Z完成q些事情Q?/p>
比如Q你可以使用@Stateless注释标记cLJavacd明ؓ(f)一个无状态会(x)话bean。对于有状态会(x)话bean来说Q@Remove注释可以用来标记一个特定的Ҏ(gu)Q通过q个注释来说明在调用q个Ҏ(gu)之后bean的实例将被清除掉?/p>
Z减少描述lg的说明信息,规范l织q采U了由异常进行配|(configuration-by-exceptionQ的手段Q意思是你可以ؓ(f)所有的注释提供一个明的~省|q样多数常规信息可以据此推断得出?/p>
新的持久化模?/p>
新的实体bean也是一个加了注释的单Java对象(POJO)。一旦它被EntityManager讉K它就成ؓ(f)了一个持久化对象Qƈ且成Z持久化上下文QcontextQ的一部分。一个持久化上下文与一个事务上下文是松耦合的;严格的讲Q它隐含的与一个事务会(x)话共存?/p>
实体关系也是通过注释来定义的QO/R映射也是Qƈ提供几种不同的数据库规范操作Q在EJB2.1中这些要通过开发h员自q设计模式或者其它技术来完成的(比如Q自增长主键{略Q?/p>
深入研究 现在是时候详l了解EJB3.0草案了。让我们开始探讨所有EJB中四U企业beanQƈ看看他们在新的规范中是什么样子?/p>
无状态会(x)话bean 在EJB3.0规范中,写一个无状态会(x)话bean(SLSB)只需要一个简单的Java文gq在cd加上@Stateless注释可以了。这个bean可以扩展javax.ejb.SessionBean接口Q但q些不是必须的?/p>
一个SLSB不再需要home接口Q没有哪cEJB再需要它了。Beancd以实C务接口也可以不实现它。如果没有实CQ何业务接口,业务接口?x)由Lpublic的方法生。如果只有几个业务方法会(x)被暴露在业务接口中,q些Ҏ(gu)可以使用@BusinessMethod注释。缺省情况下所有生的接口都是localQ本圎ͼ(j)接口Q你也可以用@Remote注释来声明这个接口ؓ(f)remoteQ远E)(j)接口?/p>
下面的几行代码就可以定义一个HelloWorldbean了。而在EJB2.1中同L(fng)bean臛_需要两个接口,一个实现类和几个空的实现方法,再加上部|描q符。 mport javax.ejb.*; /** * A stateless session bean requesting that a remote business * interface be generated for it. */ @Stateless @Remote public class HelloWorldBean { public String sayHello() { return "Hello World!!!"; } } 有状态会(x)话bean 除了几个SFSB的特别说明之外,有状态会(x)话bean(SFSB)和SLSB一L(fng)Q?/p>
1) 一个SFSB应该有一个方法来初始化自己(在EJB2.1中是通过ejbCreate()来实现的Q。在EJB3.0的规范中q些初始化操作可以通过自定义方法完成,q把他们暴露在业务接口中。在使用q个bean之前由客L(fng)来调用相应的初始化方法。目前规范组l就是否提供一个注释来标记某个Ҏ(gu)用于初始化还存在争议?/p>
2) Bean的提供者可以用@Remove注释来标CQ何SFSB的方法,以说明这个方法被调用之后bean的实例将被移除。同P规范l织仍然在讨论是否要有一U机制来处理q种Ҏ(gu)的情况,卛_q个Ҏ(gu)出现异常的情况下bean的实例是否被U除?/p>
下面是对以上问题我个人的观点Q?/p>
1) 是否应该有一个注释来标明一个方法进行初始化呢?我的观点是――应该有Q这样容器就可以在调用其他方法之前至调用一个方法来q行初始化。这不仅可以避免不必要的错误(׃没有调用初始化方?而且可以使容器更明确的判断是否可以重用SFSB实例。我暂且把这个问题放一放,规范l织只考虑Z个方法提供一个注释来声明它是一个初始化Ҏ(gu)?/p>
2) 对于W二个问题我的观点也是肯定的。这有利于Bean的提供者合客户端程序对其进行控制。只有一个遗留的问题Q那是一旦调用这个方法失败,是否能移除这个bean 的实例?{案是不能,但是它将?x)在会(x)话l束的时候被U除?/p>
消息驱动Bean 消息驱动Bean是唯一一U必dC个业务接口的Bean。这个接口指出bean支持的是哪一U消息系l。对于以JMS为基的MDB来说Q这个接口是javax.jms.MessageListener。注意MDB业务接口不是一个真正意义上的业务接口,它只是一个消息接口?/p>
实体Bean 1) 实体Bean使用@Entity注释来标讎ͼ所有实体bean中的属?字段不必使用@Transient注释来标记。实体bean的持久化字段可以通过JavaBean-style机制或者声明ؓ(f)public/protected字段来实现?/p>
2) 实体bean可以使用助手cL描述其状态,但是q些cȝ实例q没有持久化唯一性(persistent identityQ的Ҏ(gu)?卻I唯一标识q个bean的字D늭)Q实际上q些助手cM他们的实体bean实例是紧密结合的Qƈ且这些对象还是以非共享方式来讉K实体对象的?/p>
实体兌 EJB3.0同时支持Bean之间双向的合单向的关联,它们可以是一对一、一对多、多对一或者是多对多的兌。然而双向关联的两端q要分ؓ(f)自n端(owning sideQ和Ҏ(gu)端(inverse sideQ不同的端。自w端负责向数据库通告兌的变更。对于多对多的关联自w端必须明确的声明。实际上Ҏ(gu)端通过isInverse=trueq行注释Q由此自w端׃必说明了而是由另一D|断出Q。看来上面的描述Q规范组l还能说让EJB变的单了吗? O/R映射 EJB3.0中的O/R映射模型也有了重要的改变Q它从原来的abstract-persistence-schema-based变成了现在的Hibernate-inspired模式。尽目前规范组l还在就此进行讨Z是一个明的模型会(x)出现在下一个版本的草案中?/p>
举例来说QO/R映射模型通过beancM的注释来声明。而且此方法还?x)指出对应的具体表和字段。O/R映射模型提供了一套自有的SQLQ而且除了提供一些基本的SQL外还支持某些高层开发的功能。比如,有一个通过@Column注释声明的字DcolumnDefinitionQ那么可以写q样的SQLQcolumnDefinition="BLOB NOT NULL" 客户端程序模?/p>
一个EJB客户端可以通过@Inject注释以一U?#8220;注入”的方式获得一个bean的业务接口引用。你也可以用另一个注释@javax.ejb.EJBContext.lookup()来完成上面的操作Q但是规范中没有告诉我们一个普通的Java客户端怎样获得一个Bean的实例,因ؓ(f)q个普通的Java客户端是q行在一个客L(fng)容器中,它无法访问@javax.ejb.EJBContex对象。现在还有另外一U机制来完成上面的工作那是使用一个超U上下文环境对象Q@javax.ejb.Context()。但是规范中没有指出该如何在客户端中使用q个对象?/p>
EJB QL EJB QL可以通过@NamedQuery来注释。这个注释有两个成员属性分别是name和queryString.一旦定义了q些属性,可以通过EntityManager.createNamedQuery(name)来指向这个查询。你也可以创Z个标准的JDBC风格的查询ƈ使用EntityManager.createQuery(ejbqlString)或EntityManager.createNativeQuery(nativeSqlString)(q个Ҏ(gu)用于执行一个本地查?来执行查询?/p>
EJB QL有两个地方可以定义其参数。javax.ejb.Query接口提供了定义参数、指向查询、更新数据等{方法。下面是一个EJBQL指向查询的例子:(x) .. .. @NamedQuery( name="findAllCustomersWithName", queryString="SELECT c FROM Customer c WHERE c.name LIKE :custName" ) .. .. @Inject public EntityManager em; customers = em.createNamedQuery("findAllCustomersWithName") .setParameter("custName", "Smith") .listResults(); 下面列出了一些EJB QL的增强特性:(x) 1) 支持扚w更新和删除?/p>
2) 直接支持内连接和外连接。FETCH JOINq行你指出关联的实体QOrder可以指定只查询某个字Dc(din)?/p>
3) 查询语句可以q回一个以上的l果倹{实际上Q你可以q回一个依赖的cL如下面这P(x) SELECT new CustomerDetails(c.id, c.status, o.count) FROM Customer c JOIN c.orders o WHERE o.count > 100 4) 支持group by 和having?/p>
5) 支持where子句的嵌套子查询?/p>
在提交的EJB3.0草案中,EJB QL与标准SQL非常的接q。实际上规范中甚至直接支持本地的SQL(像我们上面提到的那?。这一点对某些E序员来说也许有些不是很清楚Q我们将在下面进行更详细的讲解?/p>
多样?/p>
Ҏ(gu)许可(Method permissions)可以通过@MethodPermissions或@Unchecked注释来声明;同样的,事务属性也可以通过@TransactionAttribute注释来声明。规范中仍然保留资源引用和资源环境引用。这些一样可以通过注释来声明,但是有一些细微的差别。比如,上下?context)环境要通过注入工具控制。容器根据bean对外部环境引用自动初始化一个适当的已l声明的实例变量。比如,你可以象下面q样获得一个数据源QDataSourceQ:(x) @Resource(name="myDataSource") //Type is inferred from variable public DataSource customerDB; 在上面的例子中如果你不指定引用资源的名称(name)那么其中的customerDB?x)被认?f)是默认倹{当所有的引用属性都可得到时Q@Injec注释可以这样写Q @Inject public DataSource customerDB; 容器负责在运行时初始化customerDB数据源实例。部|h员必d此之前在容器中定义好q些资源属性?/p>
更好的消息是Q那些以前必L的异常一M复返。你可以声明L的应用程序异常,而不必在再抛出或捕获其他cMCreateException和FinderExceptionq样的异常。容器会(x)抛出装在javax.ejb.EJBException中的pȝU异常或者只在必要时候抛出IllegalArgumentException或IllegalStateException异常?/p>
EJB文g处理模式 在我们结束本节之前,让我的快速的览一下容器提供商在EJB处理模式斚w可能的变更。规范中Ҏ(gu)q没有明的表态,但我可以惛_臛_两种模式?/p>
1) 一U办法是首先利用EJB文g生成cM于EJB2.1部v模式的文Ӟ包括必要的接口和部v描述W)(j)然后再用cM于EJB2.1的方式来部vq个EJBlg。当?dng)q样产生的部|描q符可能q不标准但是它可以解军_一个容器对EJB2.1和EJB3.0兼容的问题。 2) 另一U方法是一U类gJSP托放的部|模式。你可以把一个EJB文g攑ֈ一个预先定义的目录下,然后容器?x)识别这个EJBq处理它Q然后部|ƈ使之可以使用。这U方法可以徏立于上面那种Ҏ(gu)之上Q在支持反复部v时有很大的帮助。考虑到部|的单性也是EJB3.0规范的目的之一Q我真诚的希望在下一个草案出来时能够定一个模?臛_能有一个非正式??/p>
你有什么想法? EJB3.0规范的制定正在有序的q行Qؓ(f)了EJB的开发变得更加容易,EJB规范l织作出的努力是有目q的。就像他们说的那P一切对?x)变得简单,但做到这一点ƈ不容易。目前已l定义了50个注释标?q有几个在下一个草案中发布)Q每一个都有自q~省规则和其他的操作。当?dng)我真的不希望EJB3.0变成EJB2.1的一个翻?EJB 3.0 = EJB 2.1 for dummies"Q希望这个等式不要成立)(j)。最后,我还是忍不住要提一些我自己的观点:(x) 1) 首先Q规范确实反复部v变得Ҏ(gu)了,q且有一个简单的模式来访问运行时环境。我q是觉得home接口应该攑ּ?/p>
2) 在早期的EJB规范中,实体bean用于映射一个持久化存储。理Z(也许只是理论?可能需要把实体bean映射C个遗留的EIS(enterprise information system)pȝ中。出于将来扩展的考虑q样作是有好处的Qƈ且可以更多的业务数据模型采用实体bean。也因此其伴随的复杂性得实体bean不被看好。在本次提交的草案中Q一个实体bean只是一个数据库的映。ƈ且是Z非抽象持久化模式和简单的数据讉K模式的更加简单开发?/p>
3) 我对模型变更持保留态度Q我认ؓ(f)在EJB中包含SQL脚本片断q不是个好注意。一些开发h员完全反对包含某?#8220;SQL片段QSQLnessQ?#8221;Q比如@Table ?@Column注释Q。我的观Ҏ(gu)q些SQLness是好的,据此我们可以清楚的知道我们到底要数据库作些什么。但是某些SQLD|看来q不是很好,比如columnDefinition="BLOB NOT NULL"Q这使得EJB代码和SQL之间的耦合太过紧密了?/p>
4) 管对于本地SQL的支持看似很׃hQ其实在EJB代码中嵌入SQL是一个非常糟p的L。当?dng)有些办法可以避免在EJB中硬~码SQLQ但是这应该在规范中说明Q而不能是某些开发h员自己定义的模式?/p>
5) 假设@Table注释只用于类。在q行旉过@Table注释的name属性定义的表名U将必须对应一个实际的数据库表。规范对此应该给予清楚的说明和一致的模式?/p>
6) 规范q需要更清楚的说明客L(fng)~程模型Q尤其是普通java客户端。规范中所有的参考都假设或者隐含的使用EJB客户端。而且规范中对客户端的向后兼容斚w也没有给出明的说法?/p>
7) Transient注释应该重新命名以避免和已有的transient关键字发生冲H。事实上Q在q一点上我们更乐于稍微的背离一下configuration-by-exception原则q且定义一个@Persistent注释来明的定义持久化字Dc(din)@Persistent注释可以仅仅是一个标记注释或者它可以有几个属性来兌O/R映射注释?/p>
与其他规范的兌 目前可能影响到EJB3.0的JSR有JSR175Qjava语言元数据工P(j)和JSR181QJava Web服务元数据)(j) JSR175已经初步完成q且不会(x)和EJB3.0有太大的冲突Q但是JSR181与EJB3.0有两个关联的地方Q?/p>
1) Web service接口QEJB规范?yu)采用一U机刉应JSR181以便可以把一个bean实现Z个Web serviceq告诉Web service如何被客L(fng)调用?/p>
2) JSR 181计划采用不同的机制来处理安全问题。在早期的规范中EJB使用一个一致的机制QMethodPermissionsQ,但是JSR 181计划使用一个稍微不同的方式QSecurityRoles和SecurityIdentity注释Q。同L(fng)RunAs注释的定义也存在q些许差别。这一问题q在解决中最l会(x)在J2EE层的规范中维持其一致性?/p>
在J2EE 1.5中的一些开发规范可能与EJB3.0有关联。除了上面说到的几个兌之外现在没有其他的开发规范与EJB3.0有冲H?/p>
l束?/p>
在EJB的开发变得简单高效之前,我们q有很长一D\要走。规范组l在降低EJB的开发难度方面v了个好头。O/R映射模型的提议还处在早期阶段Q规范组l正在完善它。我希望它不要太复杂也不要与SQLq分的耦合。让我们不要只是停留在期望、希望、思考和h中:(x)提出你的xq把你的发送给规范l织ejb3-feedback@sun.com。JCPq不是很民主的组l,但是你的一定是有h(hun)值的?/font> 在Component-Base和N-Tier潮流下,无状态(statelessQ物件扮演着重要的角艌Ӏstateless物g?OO 和Transaction Service两项技术结合的产物。OO 技术强调的是弹性(felxibilityQ、重用性(reusabilityQ和分散?distribution)QTransaction Service技术强调的是效率(performanceQ和延展性(scalabilityQ?Stateless物g是这两项技术结合的重要支柱?/font> 传统的OO技术大多着重于 Stateful 物gQ然而在今天的MiddleWareQ如EJB?COM+/MTSQ里面,Stateless物g的地位却q远高于Stateful物g。尤其是在EJB的架构里QStateless有着非常重要的用途。例如Stateless的Session物g不需要长期保存自w的状态|也不专属于特定的用户QclientQ,所以占用的服务器资源非怹,也由于不隶属于特定的用户Q所以许多EJB物g可以q数的Stateless物g?/font> Stateless物g的特?/font> Client而言Q在意的是server物g的外在行为,而行为又和物件的状态无兟뀂所以client物g不必在意物g状态的变化Q而不是此 U物件真的没有状态。比如说stateless的限制ƈ不意味着stateless的session beans不能拥有属性变量,所以,q些session beans一样会(x)拥有自己的内部状态,然而重要的是,client不会(x)看到q些内部状态?/font> 在Internet时代里,资讯pȝ的扩展性(scalabilityQ显得无比重要,而高度扩展性的前提是必L效运用Server的资源,而无状态的物g的资源共用性极大地减少了服务器的负载,因此Q在开发N-Tierpȝ的时候,zȝStateless物g是系l开发h员必d有的技能之一?/font> 使用Stateless支持交易 当企业资讯系l的Client数目大幅度增加的时候,每个Client能够享有的共用资源(shared resourcesQ自然会(x)更加E。面对这个问题,除了投入更多的资源之外,好好协调以避免资源的费Q达到充分共享,也是重要的解决之道?/font> 其中Q数据库是最典型的稀有共享资源,交易是协调这共享资源的可靠技术,如果加上Stateless物gQ交易就?x)更加具有威?-更有效运用数据库的connectionQƈ能跨不同的数据库(卛_布式交易Q?/font> 交易是商业往来或异动的事ӞeventQ?。事件一旦发生,企业资讯pȝ׃(x)参与q行一q串的作业过E(processQ,在这个过E中Q会(x)D׃n资源Q比如数据库的资料)(j)的一q串异动。ؓ(f)了确保在异动q程中,不受到别的交易的q扰Q也Z保异动q程中的例外处理Q比如roll backQ,“交易”成为用来管理和协调q资源的工兗?/font> 在交易过E中Q需要数据库提供服务Q即资源Q,以便能够异动数据库里面的资料Q完毕后把资源释放Q供彼得交易使用。在像EJB{系l的交易服务Qtransaction serviceQ里 Q都必须具备有ACIDQatomic,consistency,isolation,durationQ四个特性,来做Cq的资源理功能?/font> 一般来_(d)必须先取得和数据库的沟通管道(connectionQ?Q才能获得数据库的服务,而数据库的connection又很有限Q所以协调connection成ؓ(f)理数据库资源的重心。让每个client能尽快释放connection成ؓ(f)重要的管理工作?/font> 在交易的q行q程中,?x)取得所需的数据库q接Q一直到交易l束才会(x)释放掉,所以充分运用连接一定要注意两点Q一是交易的旉短好Q交易越短就能越快速地释放被占用的connection。二是交易所需要的connection少好Q这样就有更多的׃nZ(x)了?/font> 在component-based环境中,一个交易通常׃物件所共同合作Q每个物件可能由不同人所设计开发,每个物g也都可能向数据库索取connection。如果一个交易的参与物g多Q而且每个物g占用的connection旉长Q则q个交易需要够多的connection才能完成d?/font> 因此Q?#8220;让物件迅速释放connection” 是提升数据库资源q用效率的重要策略,stateless物g则是实现q个{略的重要技术?
public abstract class AddressEJB implements EntityBean {
public abstract void setFirstName(String name);
public abstract String getLastName();
public abstract void setLastName(String name);
public abstract String getStreet1();
public abstract void setStreet1(String name);
public abstract String getStreet2();
public abstract void setStreet2(String name);
public abstract String getCity();
public abstract void setCity(String name);
public abstract String getState();
public abstract void setState(String name);
public abstract String getCountry();
public abstract void setCountry(String name);
public abstract String getZip();
public abstract void setZip(String name);
String s2, String cy, String st,
String cnty, String pcode)
throws CreateException {
setFirstName(fName);
setLastName(lName);
setStreet1(s1);
setStreet2(s2);
setCity(cy);
setState(st);
setCountry(cnty);
setZip(pcode);
return null;
}
String street2, String city, String state,
String country, String zip)
throws CreateException{}
public void setEntityContext(EntityContext c){ context = c; }
public void unsetEntityContext(){}
public void ejbRemove() throws RemoveException {}
public void ejbActivate() {}
public void ejbPassivate() {}
public void ejbStore() {}
public void ejbLoad() {}
}
<display-name>AddressEJB</display-name>
<ejb-name>AddressEJB</ejb-name>
<local-home>com.sun.j2ee.blueprints.address.ejb.AddressLocalHome</local-home>
<local>com.sun.j2ee.blueprints.address.ejb.AddressLocal</local>
<ejb-class>com.sun.j2ee.blueprints.address.ejb.AddressEJB</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.Object</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Address</abstract-schema-name>
<field-name>firstName</field-name>
</cmp-field>
<cmp-field>
<field-name>lastName</field-name>
</cmp-field>
<cmp-field>
<field-name>street1</field-name>
</cmp-field>
<cmp-field>
<field-name>street2</field-name>
</cmp-field>
<cmp-field>
<field-name>city</field-name>
</cmp-field>
<cmp-field>
<field-name>state</field-name>
</cmp-field>
<cmp-field>
<field-name>country</field-name>
</cmp-field>
<cmp-field>
<field-name>zip</field-name>
</cmp-field>
<security-identity>
<description></description>
<use-caller-identity></use-caller-identity>
</security-identity>
</entity>
ejbStore() -->修改数据库数据UPDATE)
ejbRemove() -->删除数据库数?DELETE)
ejbCreate() -->插入新的数据记录(INSERT)
ejbFindByPrimaryKey(primary key) --> 保 primary key 存在.
ejbFindAllPrimaryKey() -->自己的定?q回一个primary key所有数据记录的collectionxiam
String s2, String cy, String st,
String cnty, String pcode) throws CreateException {
// insert row into database
this.fName = fName;
this.lName = lName;
this.s1 = s1;
this.s2 = s2;
this.cy=cy;
this.st=st;
this.cnty=cnty;
this.pcode=pcode;
try {
Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement
("INSERT INTO Address (firstName,lastName,street1,street2,city,stateQcountry,zip) VALUES (?, ?, ?,?,?,?)");
statement.setString(1, fName);
statement.setString(2, lName);
statement.setString(3, pcode);
statement.setString(4, s1);
statement.setString(5, s2);
statement.setString(6, st);
statement.setString(7, cy);
statement.setString(8, cnty);
if (statement.executeUpdate() != 1) {
statement.close();
connection.close();
throw new CreateException("Could not create: " );
}
statement.close();
connection.close();
}
catch(SQLException e) {
throw new EJBException("Could not create: " );
}
}
J2EE Design Patterns: CMP-to-BMP Pattern
]]>
概览
]]>
]]>
3、EJB3由JSR220定义Q第一个文档:(x)l合介绍新版本的高Ҏ(gu),着重介l用于构建EJBlg的新的简化模型;后两个文档:(x)分布讲解核心企业Bean框架和持久化模型的技术细节?/font>
Q?Q?EJB3化APIQEJB3 Simplified APIQ高度概括新EJB3开发模型;
Q?Q?EJB3核心U定和要求(EJB3 Core Contracts and RequirementQ重点讲解会(x)话Bean和消息驱动BeanQ?/font>
Q?Q?Java持久化APIQJava Persistence APIQ讲解实体和持久化框架?/font>
4、EJB3包括?x)话Bean和消息驱动BeanQ实体Bean由持久化提供器管理(已经不再是EJB容器理Q?/font>
5、EJB框架QEJBlg操作的支持环境,包括容器事务、安全事务、资源的池管理和~存、组件生命周期服务和q发支持{?/font>
6、EJB核心Ҏ(gu):(x)
Q?Q?声明式元数据Q用注释或XML文g声明式地指定企业Bean和实体的行ؓ(f)Q?/font>
Q?Q?只有在需要非默认行ؓ(f)Ӟ才显C的指定注释或XML—?gt;Configuration by ExceptionQ按异常配置Q;
Q?Q?可~性:(x)EJB服务器用资源池辑ֈ对象重用的最大化Q用持久化~存避免重复查询或创建相同的对象Q?/font>
Q?Q?Java事务APIQJTAQ:(x)分布式事务定义标准APIQƈ且EJB服务器作为EJB的JTA事务理器;
Q?Q?多层安全
Q?Q?可移植性:(x)EJB可移植到实现EJB的Q何AS上;
Q?Q?可重用性:(x)可重用或打包到多个应用程序中Q?/font>
Q?Q?持久性:(x)实体Bean—?gt; 在EJB中替换ؓ(f)POJO. 7、XML和注释,同时使用时XML配置文g优先?/font>
8、依赖注入:(x)在JavaEE容器内实例化一个EJB之后Q且在把安全交付l客户之前,容器可以按照此企业Bean定义的原则初始化实例的属性数据?/font>
9、拦截器Q回调方法。企业Bean或实体Bean在遇到特定的生命周期事gӞ指定调用它们自己的或其它特定cȝҎ(gu)?/font>
10、POJO实现Q默认的构造器替换了早期EJB要求的ejbCreateQ)(j)Ҏ(gu)。实体Bean的Home接口比替换ؓ(f)EntityManager接口Q它是单一实例工厂Q管理实体生命周期的操作?/font>
11、分布式计算模型12、EJB角色
Q?Q?企业Bean提供?/font>
Q?Q?应用E序装配?/font>
Q?Q?部v?/font>
一.Enterprise Beans
在EJBQEnterprise Java BeansQ中定义了两U不同类别的Enterprise Bean Q?br />
*?x)?Bean (Session Bean)
*实体Bean (Entity Bean)
1. ?x)?Bean (Session Bean)
?x)?Bean 是调用它的客L(fng)代码要完成的工作。当客户端与服务器徏立联p,那么一个会(x)?Bean 徏立v来了。根据会(x)?Bean 的状态不同有分ؓ(f):
A. 状态会(x)?Bean (Stateful Session Bean)
B. 无状态会(x)?Bean (Stateless Session Bean)
1.1 状态会(x)?Bean (Stateful Session Bean)
当客h和服务器建立q接之后Q状态会(x)?Bean (Stateful Session Bean) 一直在客户机和服务器之间保持着用户的某个状态。例如:(x)用户使用银行的ATMӞl过验证之后Q用户可以连l执行多ơ操作,在这个过E当中,用户的合法状态将一直被保留Q直到她信用卡取出Q结束这ơ操作。这Ӟ状态会(x)?Bean (Stateful Session Bean) 也就被销毁?br />
1.2无状态会(x)?Bean (Stateless Session Bean)
当客h和服务器建立q接之后Q无状态会(x)?Bean (Stateless Session Bean)处理单一的用戯求或商务q程。无状态会(x)?Bean (Stateless Session Bean)不需要从以前的请求中提取M状态。例如,用户的用户密码确认。用戯入密码后Q发送请求。组件返回真或假来确认用P一旦过E完成,无状态会(x)?Bean (Stateless Session Bean) 也宣告结束?br />
2. 实体Bean (Entity Bean)
实体Bean (Entity Bean)只是数据模型Q它不包括商务逻辑。实体Bean (Entity Bean)可以关p?对象数据库的数据映射到内存中供其它组件用。实体Bean (Entity Bean)是一直存在的Q而且h很高的容错性能。实体Bean (Entity Bean)能供允许多用户同时访问?/font>
? ?x)?Bean (Session Bean)
Ejb的执行过E是被放在一个EJB容器中进行的Q所以客L(fng)不会(x)直接调用我们写好的Enterprise Bean Q而是调用EJB容器生成的一个EJBObject (EJB对象)来实现。那么,我们在编写服务器端的Enterprise Bean Ӟp考虑q点。既然客L(fng)不能直接讉KQ就由EJBObject来代劻I所以在~写服务器端Ӟp~写服务器端的一个接口(RemoteQ用来与客户p,实力化EJBObject。要生成EJBObject p调有Home 接口Q来建立q个实力?/font>
以下是会(x)?Bean 的代码分析:(x)
A.Enterprise Bean c:(x)sailorsy.class
1.setSessionContext(SessionContext ctx)Ҏ(gu)
它是EJB容器和Enterprise Bean互相作用的关口?/p>
import java.rmi.*;import javax.ejb.*;public class sailorsy implements SessionBean{private SessionContext ctx=null;public voic setSessionContext(SessionContext ctx){this.ctx=ctx;}//setSessionContext}//class sailorsy
2.ejbCreate(…)Ҏ(gu)
它可以初始化Enterprise Bean ,可以定义不同的ejbCreate(…)Ҏ(gu)Q每个方法所带的参数不同。但是,必许要存在至一U?/p>
import java.rmi.*; import javax.ejb.*;public class sailorsy implements SessionBean{private SessionContext ctx=null;public voic setSessionContext(SessionContext ctx){this.ctx=ctx;}//setSessionContext public void ejbCreate() { }//ejbCreate}//class sailorsy
3.ejbPassivate()Ҏ(gu)
如果初始化的Enterprise Bean q多QEJB容器其中的一些挂PpassivateQ?释放他们所占用的空间?/p>
import java.rmi.*; import javax.ejb.*;public class sailorsy implements SessionBean{private SessionContext ctx=null;public voic setSessionContext(SessionContext ctx){this.ctx=ctx;}//setSessionContext public void ejbCreate() { }//ejbCreate public void ejbPassivate() { }//ejbPassivate}//class sailorsy
4.ejbActivate()Ҏ(gu)
和ejbPassivate正好相反Q它?yu)被挂v的Bean从新调回?/p>
import java.rmi.*; import javax.ejb.*;public class sailorsy implements SessionBean{private SessionContext ctx=null;public voic setSessionContext(SessionContext ctx){this.ctx=ctx;}//setSessionContext public void ejbCreate() { }//ejbCreate public void ejbPassivate() { }//ejbPassivate public void ejbActivate() { }//ejbActivate}//class sailorsy
5.ejbRemove()Ҏ(gu)
它可以清除EJB容器中的Bean?/p>
import java.rmi.*; import javax.ejb.*;public class sailorsy implements SessionBean{private SessionContext ctx=null;public voic setSessionContext(SessionContext ctx){this.ctx=ctx;}//setSessionContext public void ejbCreate() { }//ejbCreate public void ejbPassivate() { }//ejbPassivate public void ejbActivate() { }//ejbActivate public void ejbRemove() { }//ejbRemove public String showname(){ return "Hello,my name is sailorsy"; }//自己的商务方法}//class sailorsy
以上q些是EJB必需的回调方法,我们可以在里面加入自qҎ(gu)Q加入自q商务逻辑?br /> B.Home 接口: sailorsyHome
import java.rmi.*;import javax.ejb.*;public interface sailorsyHome extends EJBHome { public sailorsyRemote create() throws RemoteException, CreateException;}C. Remote接口QsailorsyRemoteimport java.rmi.*;import javax.ejb.*;public interface sailorsyRemote extends EJBObject { public java.lang.String showname() throws RemoteException;}
?调用?x)?BeanQsailorsyTestClient1
import javax.naming.*;import javax.ejb.*;import javax.rmi.PortableRemoteObject;import java.rmi.*;public class sailorsyTestClient1 { private sailorsyHome sailorsyHomeObject = null; //Construct the EJB test client public sailorsyTestClient1() { try { //以下是客L(fng)使用JNDI定位Home对象?nbsp; Context ctx = new InitialContext(); //look up jndi name Object ref = ctx.lookup("sailorsy"); //cast to Home interface sailorsyHomeObject = (sailorsyHome) PortableRemoteObject.narrow(ref, sailorsyHome.class); } catch(Exception e) { e.printStackTrace(); } } //---------------------------------------------------------------------------- // Utility Methods //---------------------------------------------------------------------------- public sailorsyHome getHome() { return sailorsyHomeObject; } //Main method public static void main(String[] args) throws Exception{ sailorsyTestClient1 client = new sailorsyTestClient1(); sailorsyRemote sr=client.getHome() .create() ; String s=sr.showname() ; System.out.print(s); // Use the getHome() method of the client object to call Home interface // methods that will return a Remote interface reference. Then // use that Remote interface reference to access the EJB. }}
以上的EJB在win2000+jbuilder5/jbuilder6+BAS4.5l过试?/p>
以下是整个EJB的执行过E:(x)
1. 客户端通过JNDI(g)索Home对象的引用;
2. JNDIq回Home对象的引用;
3. h创徏一个新的EJB对象Q?br />
4. 创徏EJB对象Q?br />
5. q回EJB对象Q?br />
6. 调用商务Ҏ(gu)Q?br />
7. 调用Enterprise Bean.
1、EJB2.0有哪些内?分别用在什么场? EJB2.0和EJB1.1的区?
{:(x)规范内容包括Bean提供者,应用E序装配者,EJB容器QEJB配置工具QEJB服务提供者,pȝ理员。这里面QEJB容器是EJB之所以能够运行的核心。EJB容器理着EJB的创建,撤消Q激z,LQ与数据库的q接{等重要的核心工作。JSP,Servlet,EJB,JNDI,JDBC,JMS.....
2、EJB与JAVA BEAN的区?
{:(x)Java Bean 是可复用的组Ӟ对Java Beanq没有严格的规范Q理ZԌM一个Javac都可以是一个Bean。但通常情况下,׃Java Bean是被容器所创徏(如Tomcat)的,所以Java Bean应具有一个无参的构造器Q另外,通常Java Beanq要实现Serializable接口用于实现Bean的持久性。Java Bean实际上相当于微YCOM模型中的本地q程内COMlgQ它是不能被跨进E访问的。Enterprise Java Bean 相当于DCOMQ即分布式组件。它是基于Java的远E方法调?RMI)技术的Q所以EJB可以被远E访?跨进E、跨计算?。但EJB必须被布|在诸如Webspere、WebLogicq样的容器中QEJB客户从不直接讉K真正的EJBlgQ而是通过其容器访问。EJB容器是EJBlg的代理,EJBlg由容器所创徏和管理。客户通过容器来访问真正的EJBlg?/font>
3、EJB是基于哪些技术实现的?q说出SessionBean和EntityBean的区别,StatefulBean和StatelessBean的区别?/font>
{:(x)EJB包括Session Bean、Entity Bean、Message Driven BeanQ基于JNDI、RMI、JAT{技术实现?/font>
SessionBean在J2EE应用E序中被用来完成一些服务器端的业务操作Q例如访问数据库、调用其他EJBlg。EntityBean被用来代表应用系l中用到的数据?/font>
对于客户机,SessionBean是一U非持久性对象,它实现某些在服务器上q行的业务逻辑?/font>
对于客户机,EntityBean是一U持久性对象,它代表一个存储在持久性存储器中的实体的对象视图,或是一个由现有企业应用E序实现的实体?/font>
Session Bean q可以再l分?Stateful Session Bean ?Stateless Session Bean Q这两种?Session Bean都可以将pȝ逻辑攑֜ method之中执行Q不同的?Stateful Session Bean 可以记录呼叫者的状态,因此通常来说Q一个用者会(x)有一个相对应?Stateful Session Bean 的实体。Stateless Session Bean 虽然也是逻辑lgQ但是他却不负责记录使用者状态,也就是说当用者呼?Stateless Session Bean 的时候,EJB Container q不?x)找ȝ定?Stateless Session Bean 的实体来执行q个 method。换a之,很可能数个用者在执行某个 Stateless Session Bean ?methods Ӟ?x)是同一?Bean ?Instance 在执行。从内存斚w来看Q?Stateful Session Bean ?Stateless Session Bean 比较Q?Stateful Session Bean ?x)消?J2EE Server 较多的内存,然?Stateful Session Bean 的优势却在于他可以维持用者的状态?/font>
4、EJB与JAVA BEAN的区?
{:(x)Java Bean 是可复用的组Ӟ对Java Beanq没有严格的规范Q理ZԌM一个Javac都可以是一个Bean。但通常情况下,׃Java Bean是被容器所创徏(如Tomcat)的,所以Java Bean应具有一个无参的构造器Q另外,通常Java Beanq要实现Serializable接口用于实现Bean的持久性。Java Bean实际上相当于微YCOM模型中的本地q程内COMlgQ它是不能被跨进E访问的。Enterprise Java Bean 相当于DCOMQ即分布式组件。它是基于Java的远E方法调?RMI)技术的Q所以EJB可以被远E访?跨进E、跨计算?。但EJB必须被布|在诸如Webspere、WebLogicq样的容器中QEJB客户从不直接讉K真正的EJBlgQ而是通过其容器访问。EJB容器是EJBlg的代理,EJBlg由容器所创徏和管理。客户通过容器来访问真正的EJBlg?/font>
EJB包括(SessionBean,EntityBean)说出他们的生命周期,?qing)如何管理事务?
SessionBeanQStateless Session Bean 的生命周期是由容器决定的Q当客户机发求要建立一个Bean的实例时QEJB容器不一定要创徏一个新的Bean的实例供客户用,而是随便找一个现有的实例提供l客h。当客户机第一ơ调用一个Stateful Session Bean Ӟ容器必须立即在服务器中创Z个新的Bean实例Qƈ兌到客h上,以后此客h调用Stateful Session Bean 的方法时容器?x)把调用分派C此客h相关联的Bean实例?/font>
EntityBeanQEntity Beans能存?gu)zȝ对较长的旉Qƈ且状态是持箋的。只要数据库中的数据存在QEntity beans׃直存?gu)zR而不是按照应用程序或者服务进E来说的。即使EJB容器崩溃了,Entity beans也是存活的。Entity Beans生命周期能够被容器或?Beans自己理?/font>
EJB通过以下技术管理实务:(x)对象理l织(OMG)的对象实务服?OTS)QSun Microsystems的Transaction Service(JTS)、Java Transaction API(JTA)Q开发组(X/Open)的XA接口?/font>
5、EJB的角色和三个对象
{:(x)一个完整的ZEJB的分布式计算l构由六个角色组成,q六个角色可以由不同的开发商提供Q每个角色所作的工作必须遵@Sun公司提供的EJB规范Q以保证彼此之间的兼Ҏ(gu)。这六个角色分别是EJBlg开发?Enterprise Bean Provider) 、应用组合?Application Assembler)、部|?Deployer)、EJB 服务器提供?EJB Server Provider)、EJB 容器提供?EJB Container Provider)、系l管理员(System Administrator)
三个对象是Remote(Local)接口、Home(LocalHome)接口QBeanc?/font>
6、EJB容器提供的服?/font>
{:(x)主要提供声明周期理、代码生、持l性管理、安全、事务管理、锁和ƈ发行理{服务?/font>
7、EJB规范规定EJB中禁止的操作有哪?
{:(x)1.不能操作U程和线EAPI(U程API指非U程对象的方法如notify,wait{?Q?.不能操作awtQ?.不能实现服务器功能,4.不能寚w态属生存取,5.不能使用IO操作直接存取文gpȝQ?.不能加蝲本地?Q?.不能this作ؓ(f)变量和返回,8.不能循环调用?/font>
8、remote接口和home接口主要作用
{:(x)remote接口定义了业务方法,用于EJB客户端调用业务方法?/font>
home接口是EJB工厂用于创徏和移除查找EJB实例
9、bean 实例的生命周?/font>
{:(x)对于Stateless Session Bean、Entity Bean、Message Driven Bean一般存在缓冲池理Q而对于Entity Bean和Statefull Session Bean存在Cache理Q通常包含创徏实例Q设|上下文、创建EJB Object(create)、业务方法调用、remove{过E,对于存在~冲池管理的BeanQ在create之后实例q不从内存清除,而是采用~冲池调度机制不断重用实例,而对于存在Cache理的Bean则通过ȀzdLzL制保持Bean的状态ƈ限制内存中实例数量?/font>
10、EJB的激zL?/font>
{:(x)以Stateful Session Bean ZQ其Cache大小军_了内存中可以同时存在的Bean实例的数量,Ҏ(gu)MRU或NRU法Q实例在ȀzdLzȝ态之间迁U,ȀzL制是当客L(fng)调用某个EJB实例业务Ҏ(gu)Ӟ如果对应EJB Object发现自己没有l定对应的Bean实例则从其去ȀzBean存储?通过序列化机制存储实?回复(Ȁz?此实例。状态变q前?x)调用对应的ejbActive和ejbPassivateҎ(gu)?/font>
11、EJB的几U类?/font>
{:(x)?x)?Session)Bean Q实?Entity)Bean 消息驱动?Message Driven)Bean
?x)话Bean又可分ؓ(f)有状?Stateful)和无状?Stateless)两种
实体Bean可分为Bean理的持l?BMP)和容器管理的持箋?CMP)两种
12、客服端调用EJB对象的几个基本步?/font>
{:(x)讄JNDI服务工厂以及(qing)JNDI服务地址pȝ属性,查找Home接口Q从Home接口调用CreateҎ(gu)创徏Remote接口Q通过Remote接口调用其业务方法?/font>