WEB开发网      濠电姷鏁告慨鐑藉极閸涘﹦绠鹃柍褜鍓氱换娑欐媴閸愬弶鎼愮痪鍓ф嚀閳规垿鎮╃€圭姴顥濋梺姹囧€楅崑鎾诲Φ閸曨垰绠涢柛顐f礃椤庡秹姊虹粙娆惧剳闁哥姵鍔欐俊鐢稿礋椤栨艾鍞ㄩ梺闈浤涙担鎻掍壕闁圭儤顨嗛埛鎺楁煕閺囥劌浜滄い蹇e弮閺屸€崇暆鐎n剛鏆犻柧浼欑到閵嗘帒顫濋悡搴d画缂佹鍨垮缁樻媴缁涘娈┑顔斤公缁犳捇銆佸鎰佹▌濠电姭鍋撳ù锝囩《閺€浠嬫煟濡鍤嬬€规悶鍎辫灃闁绘ê寮堕崯鐐电磼閸屾氨效鐎规洘绮忛ˇ瀵哥棯閹佸仮鐎殿喖鐖煎畷鐓庘槈濡警鐎崇紓鍌欑劍椤ㄥ棗鐣濋幖浣歌摕闁绘棃顥撻弳瀣煟濡も偓閻楀棗鈻撳Δ鍛拺閻犲洠鈧櫕鐏€闂佸搫鎳愭慨鎾偩閻ゎ垬浜归柟鐑樼箖閺呮繈姊洪棃娑氬婵☆偅鐟╅、娆掔疀閺冨倻鐦堥梺姹囧灲濞佳勭閿曞倹鐓曢柕濞垮劤閸╋絾顨ラ悙鏉戝妤犵偞锕㈤、娆撴嚃閳哄骞㈤梻鍌欐祰椤鐣峰Ο鑲╃煋妞ゆ棁锟ユ禍褰掓煙閻戞ɑ灏ù婊冪秺濮婅櫣绱掑Ο铏逛桓闂佹寧娲嶉弲娑滅亱闂佸憡娲﹂崹閬嶅煕閹达附鐓欓柤娴嬫櫅娴犳粌鈹戦垾鐐藉仮闁诡喗顨呴埥澶愬箳閹惧褰囩紓鍌欑贰閸犳牠顢栭崨鎼晣闁稿繒鍘х欢鐐翠繆椤栨粎甯涙繛鍛喘濮婄粯鎷呴悷閭﹀殝缂備浇顕ч崐鍨嚕缂佹ḿ绡€闁搞儯鍔嶅▍鍥⒑缁嬫寧婀扮紒瀣崌瀹曘垽鎮介崨濠勫幗闁瑰吋鐣崹濠氬煀閺囥垺鐓ユ慨妯垮煐閻撶喖鐓崶銉ュ姢缂佸宕电槐鎺旂磼濡偐鐣虹紓浣虹帛缁诲牆鐣峰鈧俊姝岊槺缂佽鲸绻堝缁樻媴缁涘娈愰梺鎼炲妺閸楀啿鐣烽鐐茬骇闁瑰濮靛▓楣冩⒑缂佹ɑ鈷掗柍宄扮墦瀵偊宕掗悙瀵稿幈闂佹娊鏁崑鎾绘煛閸涱喚鎳呮俊鍙夊姇铻i悶娑掑墲閺傗偓闂備胶绮崝鏇炍熸繝鍥у惞闁绘柨鐨濋弨鑺ャ亜閺冨洦顥夐柛鏂诲€濋幗鍫曟倷閻戞ḿ鍘遍梺鍝勬储閸斿本鏅堕鐐寸厱婵炲棗绻掔粻濠氭煛鐏炵晫效鐎规洦鍋婂畷鐔碱敆閳ь剙鈻嶉敐鍥╃=濞达絾褰冩禍鐐節閵忥絾纭炬い鎴濇川缁粯銈i崘鈺冨幍闁诲孩绋掑玻璺ㄧ不濮椻偓閺屻劌鈽夊Ο澶癸絾銇勯妸锝呭姦闁诡喗鐟╅、鏃堝礋椤撴繄绀勯梻鍌欐祰椤曟牠宕伴弽顐ょ濠电姴鍊婚弳锕傛煙椤栫偛浜版俊鑼额嚙閳规垿鍩勯崘銊хシ濡炪値鍘鹃崗妯侯嚕鐠囨祴妲堥柕蹇曞閳哄懏鐓忓璺虹墕閸旀挳鏌涢弬娆炬Ш缂佽鲸鎸婚幏鍛矙鎼存挸浜鹃柛婵勫劤閻挾鎲搁悧鍫濈瑨闁哄绶氶弻鐔煎礈瑜忕敮娑㈡煛閸涱喗鍊愰柡灞诲姂閹倝宕掑☉姗嗕紦 ---闂傚倸鍊搁崐鎼佸磹閻戣姤鍊块柨鏃堟暜閸嬫挾绮☉妯哄箻婵炲樊浜滈悡娑㈡煕濞戝崬骞樻い鏂挎濮婅櫣鎹勯妸銉︾彚闂佺懓鍤栭幏锟�
开发学院WEB开发Jsp J2EE综合:关于Java EJB容器存取和实现 阅读

J2EE综合:关于Java EJB容器存取和实现

 2008-03-05 20:37:20 来源:WEB开发网 闂傚倸鍊搁崐鎼佸磹妞嬪孩顐芥慨姗嗗厳缂傛氨鎲稿鍫罕闂備礁婀遍搹搴ㄥ窗閺嶎偆涓嶆い鏍仦閻撱儵鏌i弴鐐测偓鍦偓姘炬嫹闂傚倸鍊搁崐鎼佸磹妞嬪海鐭嗗〒姘e亾妤犵偛顦甸弫鎾绘偐閹绘帞鈧參姊哄Ч鍥х仼闁诲繑鑹鹃悾鐑藉蓟閵夛妇鍘甸梺瑙勵問閸犳牠銆傛總鍛婄厱閹艰揪绱曟牎闂侀潧娲ょ€氫即鐛幒妤€绠f繝闈涘暙娴滈箖鏌i姀鈶跺湱澹曟繝姘厵闁绘劦鍓氶悘杈ㄤ繆閹绘帞澧涚紒缁樼洴瀹曞崬螖閸愬啠鍓濈换娑樼暆婵犱胶鏁栫紓浣介哺閹瑰洤鐣烽幒鎴僵闁瑰吀鐒﹂悗鎼佹⒒娴g儤鍤€闁搞倖鐗犻獮蹇涙晸閿燂拷濠电姷鏁告慨鐑藉极閸涘﹥鍙忔い鎾卞灩缁狀垶鏌涢幇闈涙灈鐎瑰憡绻冮妵鍕箻鐎靛摜鐣奸梺纭咁潐濞茬喎顫忕紒妯肩懝闁逞屽墮宀h儻顦查悡銈夋煏閸繃鍋繛宸簻鎯熼梺瀹犳〃閼冲爼宕濋敃鈧—鍐Χ閸℃鐟愰梺鐓庡暱閻栧ジ宕烘繝鍥у嵆闁靛骏绱曢崢顏堟⒑閹肩偛鍔楅柡鍛⊕缁傛帟顦寸紒杈ㄥ笚濞煎繘鍩℃担閿嬵潟闂備浇妗ㄩ悞锕傚箲閸ヮ剙鏋侀柟鍓х帛閺呮悂鏌ㄩ悤鍌涘闂傚倸鍊搁崐鎼佸磹妞嬪孩顐芥慨姗嗗厳缂傛氨鎲稿鍫罕闂備礁婀遍搹搴ㄥ窗閺嶎偆涓嶆い鏍仦閻撱儵鏌i弴鐐测偓鍦偓姘炬嫹  闂傚倸鍊搁崐鎼佸磹閻戣姤鍤勯柤鍝ユ暩娴犳氨绱撻崒娆掑厡缂侇噮鍨堕妴鍐川閺夋垹鍘洪悗骞垮劚椤︻垶宕¢幎鑺ョ厪闊洦娲栨牎闂佽瀵掗崜鐔奉潖閾忓湱纾兼俊顖氭惈椤矂姊虹拠鑼婵ǜ鍔戦崺鈧い鎺嶇閸ゎ剟鏌涢幘璺烘瀻妞ゎ偄绻愮叅妞ゅ繐瀚悗顓烆渻閵堝棙绀€闁瑰啿閰e畷婊勫鐎涙ǚ鎷洪梻渚囧亞閸嬫盯鎳熼娑欐珷妞ゆ柨澧界壕鐓庮熆鐠虹尨鍔熺紒澶庢閳ь剚顔栭崰鏍€﹂柨瀣╃箚婵繂鐭堝Σ鐑芥⒑缁嬫鍎愰柟鐟版搐铻為柛鎰╁妷濡插牊绻涢崱妤冪婵炲牊锕㈠缁樻媴妞嬪簼瑕嗙紓鍌氱М閸嬫挻绻涚€涙ḿ鐭ら柛鎾跺枛瀹曟椽鍩€椤掍降浜滈柟鐑樺灥閳ь剙缍婂鎶筋敆閸曨剛鍘遍柣搴秵娴滅兘鐓鍌楀亾鐟欏嫭纾婚柛妤€鍟块锝夊磹閻曚焦鞋闂備礁鎼Λ瀵哥不閹捐钃熼柕濞炬櫆閸嬪棝鏌涚仦鍓р槈妞ゅ骏鎷�
核心提示:作为轻量级的容器,SPRing常常被认为是EJB的替代品,J2EE综合:关于Java EJB容器存取和实现,我们也相信,对于很多 (不一定是绝大多数)应用和用例,例如ContextSingleton 或者BeanFactoryLocator,他们可以载入并共享一个 BeanFactory或ApplicationCont

作为轻量级的容器,SPRing常常被认为是EJB的替代品。我们也相信,对于很多 (不一定是绝大多数)应用和用例,相对于通过EJB容器来实现相同的功能而言, Sping作为容器,加上它在事务,ORM和JDBC存取这些领域中丰富的功能支持, Spring的确是更好的选择。
  
  不过,需要特别注意的是,使用了Spring并不是说我们就不能用EJB了, 实际上,Spring大大简化了从中访问和实现EJB组件或只实现(EJB组件)其功能的复杂性。 另外,如果通过Spring来访问EJB组件服务,以后就可以在本地EJB组件,远程EJB组件, 或者是POJO(简单java对象)这些变体之间透明地切换服务的实现,而不需要修改 客户端的代码。
  
  本章,我们来看看Spring是如何帮助我们访问和实现EJB组件的。尤其是在访问 无状态session Bean(SLSBs)的时候,Spring特别有用,现在我们就由此开始讨论。
  
  访问EJB 1.1. 概念要调用本地或远程无状态Session Bean上的方法,通常客户端的代码必须 进行JNDI查找,得到(本地或远程的)EJB Home对象,然后调用该对象的"create" 方法,才能得到实际的(本地或远程的)EJB对象。前后调用了不止一个EJB组件 上的方法。
  
  为了避免重复的底层调用,很多EJB应用使用了服务定位器(Service Locator) 和业务委托(Bussiness Delegate)模式,这样要比在客户端代码中到处进行JNDI 查找更好些,不过它们的常见的实现都有明显的缺陷。例如:
  
  通常,若是依赖于服务定位器或业务代理单件来使用EJB,则很难对代码进 行测试。
  
  在仅使用了服务定位器模式而不使用业务委托模式的情况下,应用程序 代码仍然需要调用EJB Home组件的create方法,还是要处理由此引入的异常。 导致代码仍然保留了与EJB API的耦合性以及EJB编程模型的复杂性。
  
  实现业务委托模式通常会导致大量的冗余代码,因为我们不得不编写 很多方法,而它们所做的仅仅是调用EJB组件的同名方法。
  
  Spring采用的方法是允许创建并使用代理对象,一般是在Spring的 applicationContext或BeanFactory里面进行配置,这样就和业务代理类似,只需要 少量的代码。我们不再需要另外编写额外的服务定位器或JNDI查找的代码,或者是手写 的业务委托对象里面冗余的方法,除非它们可以带来实质性的好处。
  
  1.2. 访问本地的无状态Session Bean(SLSB)
  假设有一个web控制器需要使用本地EJB组件。我们遵循前人的实践经验, 于是使用了EJB的业务方法接口(Business Methods Interface)模式,这样, 这个EJB组件的本地接口就扩展了非EJB特定的业务方法接口。让我们假定这个 业务方法接口叫MyComponent.
  
  public interface MyComponent {……
  }(使用业务方法接口模式的一个主要原因就是为了保证本地接口和bean的实现类 之间方法签名的同步是自动的。另外一个原因是它使得稍后我们改用基于POJO(简单Java对象) 的服务实现更加容易,只要这样的改变是有利的。当然,我们也需要实现 本地Home接口,并提供一个Bean实现类,使其实现接口SessionBean和业务方法接口 MyComponent.现在为了把我们Web层的控制器和EJB的实现链接起来,我们唯一要写 的Java代码就是在控制器上公布一个形参为MyComponent的setter方法。这样就可以 把这个引用保存在控制器的一个实例变量中。
  
  private MyComponent myComponent;

public void setMyComponent(MyComponent myComponent) {
   this.myComponent = myComponent;
}
  然后我们可以在控制器的任意业务方法里面使用这个实例变量。假设我们现在 从Spring的ApplicationContext或BeanFactory获得该控制器对象,我们就可以在 同一个上下文中配置一个LocalStatelessSessionProxyFactoryBean 的实例,它将作为EJB组件的代理对象。这个代理对象的配置和控制器的属性 myComponent的设置是使用一个配置项完成的,如下所示:

  class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
   myComponent
   com.mycom.MyComponent

这些看似简单的代码背后隐藏了很多复杂的处理,比如默默工作的Spring AOP框架,我们甚至不必知道这些概念,一样可以享用它的结果。Bean myComponent 的定义中创建了一个该EJB组件的代理对象,它实现了业务方法接口。这个EJB组件的 本地Home对象在启动的时候就被放到了缓存中,所以只需要执行一次JNDI查找即可。 每当EJB组件被调用的时候,这个代理对象就调用本地EJB组件的create方法,并调用 该EJB组件的相应的业务方法。
  
  在Bean myController的定义中,控制器类的属性 myController的值被设置为上面代理对象。
  
  这样的EJB组件访问方式大大简化了应用程序代码:Web层(或其他EJB客户端) 的代码不再依赖于EJB组件的使用。如果我们想把这个EJB的引用替换为一个POJO, 或者是模拟用的对象或其他测试组件,我们只需要简单地修改Bean myComponent 的定义中仅仅一行Java代码,此外,我们也不再需要在应用程序中编写任何JNDI查找 或其它EJB相关的代码。
  
  评测和实际应用中的经验表明,这种方式的性能负荷极小,(尽管其中 使用了反射方式以调用目标EJB组件的方法),通常的使用中我们几乎觉察不出。请记住 我们并不想频繁地调用EJB组件的底层方法,虽然如此,有些性能代价是与应用服务器 中EJB的基础框架相关的。
  
  关于JNDI查找有一点需要注意。在Bean容器中,这个类通常最好用作单件 (没理由使之成为原型)。不过,如果这个Bean容器会预先实例化单件(类似xml ApplicationContext的变体的行为),如果在EJB容器载入目标EJB前载入bean容器, 我们就可能会遇到问题。因为JNDI查找会在该类的init方法中被执行并且缓存结果, 这样就导致该EJB不能被绑定到目标位置。解决方案就是不要预先实例化这个工厂对象, 而允许它在第一次用到的时候再创建,在XML容器中,这是通过属性 lazy-init来控制的。
  
  尽管大部分Spring的用户不会对这些感兴趣,但那些对EJB进行AOP的具体应用 的用户则会想看看LocalSlsbInvokerInterceptor.
  
  1.3. 访问远程的无状态Session Bean(SLSB)
  基本上访问远程EJB与访问本地EJB差别不大,除了前者使用的是 SimpleRemoteStatelessSessionProxyFactoryBean.当然, 无论是否使用Spring,远程调用的语义都相同,不过,对于使用的场景和错误处理 来说,调用另外一台计算机上不同虚拟机中的对象的方法其处理有所不同。
  
  与不使用Spring方式的EJB客户端相比,Spring的EJB客户端有一个额外的 好处。通常如果客户端代码随意在本地EJB和远程EJB的调用之间来回切换,就有 一个问题。这是因为远程接口的方法需要声明其会抛出RemoteException ,然后客户端代码必须处理这种异常,但是本地接口的方法却不需要这样。 如果要把针对本地EJB的代码改为访问远程EJB,就需要修改客户端代码,增加 对RemoteException的处理,反之就需要去掉这样的 异常处理。使用Spring 的远程EJB代理,我们就不再需要在业务方法接口和EJB的 代码实现中声明会抛出RemoteException,而是定义一个 相似的远程接口,唯一不同就是它抛出的是RemoteAccessException, 然后交给代理对象去动态的协调这两个接口。也就是说,客户端代码不再需要与 RemoteException这个显式(checked)异常打交道,实际运行中 所有抛出的异常RemoteException都会被捕获并转换成一个 隐式(non-checked)的RemoteAccessException,它是 RuntimeException的一个子类。这样目标服务端就可以 在本地EJB或远程EJB(甚至POJO)之间随意地切换,客户端不再需要关心甚至 根本不会觉察到这种切换。当然,这些都是可选的,我们并不阻止在业务接口中声明 异常RemoteExceptions.
  
  2. 使用Spring提供的辅助类实现EJB组件Spring也提供了一些辅助类来为EJB组件的实现提供便利。它们是为了倡导一些 好的实践经验,比如把业务逻辑放在在EJB层之后的POJO中实现,只把事务隔离和 远程调用这些职责留给EJB.
  
  要实现一个无状态或有状态的Session Bean,或消息驱动Bean,我们的实现 可以继承分别继承AbstractStatelessSessionBean, AbstractStatefulSessionBean,和 AbstractMessageDrivenBean/AbstractJmsMessageDrivenBean
  
  考虑这个例子:我们把无状态Session Bean的实现委托给普通的Java服务对象。 业务接口的定义如下:
  
public interface MyComponent {
   public void myMethod(...);
   ...
}
  这是简单Java对象实现方式的类:

public class MyComponentImpl implements MyComponent {
   public String myMethod(...) {
     ...
   }
   ...
}
  最后是无状态Session Bean自身:

public class MyComponentEJB implements extends AbstractStatelessSessionBean
     implements MyComponent {

   MyComponent _myComp;

   /**
   * Obtain our POJO service object from the BeanFactory/ApplicationContext
   * @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate()
   */
   protected void onEjbCreate() throws CreateException {
     _myComp = (MyComponent) getBeanFactory().getBean(
       ServicesConstants.CONTEXT_MYCOMP_ID);
   }

   // for business method, delegate to POJO service impl.
   public String myMethod(...) {
     return _myComp.myMethod(...);
   }
   ...
}
  Spring为支持EJB而提供的这些基类默认情况下会创建并载入一个BeanFactory (这个例子里,它是ApplicationContext的子类),作为其生命周期的一部分, 供EJB使用(比如像上面的代码那样用来获取POJO服务对象)。载入的工作是通过 一个策略对象完成的,它是BeanFactoryLocator的子类。 默认情况下,实际使用的BeanFactoryLocator的实现类是 ContextJndiBeanFactoryLocator,它根据一个JNDI环境变量 来创建一个ApplicationContext对象(这里是EJB类,路径是 java:comp/env/ejb/BeanFactoryPath)。如果需要改变 BeanFactory或ApplicationContext的载入策略,我们可以在子类中重定义了的 setSessionContext()方法或具体EJB子类的构造函数中调用 setBeanFactoryLocator()方法来改变默认使用的 BeanFactoryLocator实现类。具体细节请参考JavaDoc.
  
  如JavaDoc中所述,有状态Session Bean在其生命周期中可能会被钝化并重新激活, 如果是不可序列化的BeanFactory或ApplicationContext,由于它们不会被EJB容器保存, 所以还需要手动在ejbPassivate和ejbActivate 这两个方法中分别调用unloadBeanFactory()和loadBeanFactory, 才能在钝化或激活的时候卸载或载入。
  
  有些情况下,要载入ApplicationContext以使用EJB组件, ContextJndiBeanFactoryLocator的默认实现基本上足够了, 不过,当ApplicationContext需要载入多个bean,或这些bean初始化所需的时间或内存 很多的时候(例如Hibernate的SessionFactory的初始化),就有可能出问题,因为 每个EJB组件都有自己的副本。这种情况下,用户会想重载 ContextJndiBeanFactoryLocator的默认实现,并使用其它 BeanFactoryLocator的变体,例如ContextSingleton 或者BeanFactoryLocator,他们可以载入并共享一个 BeanFactory或ApplicationContext来为多个EJB组件或其它客户端所公用。这样做 相当简单,只需要给EJB添加类似于如下的代码:
  
  /**
   * Override default BeanFactoryLocator implementation
   *
   * @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
   */
  public void setSessionContext(SessionContext sessionContext) {
    super.setSessionContext(sessionContext);
    setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
    setBeanFactoryLocatorKey(ServicesConstants.PRIMARY_CONTEXT_ID);
  }

Tags:JEE 综合 关于

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接