`
laoge1012
  • 浏览: 6451 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

[转]EJB与Spring的集成

阅读更多
作为一个轻量级的容器,Spring通常被认为当作是EJB的替代方案。不可否认,在许多应用场合中,Spring以其卓越的性能与丰富的事务处理、ORM、JDBC存取等功能,确实可以取代EJB。不过,我们应当注意到,Spring本身并不排斥EJB,事实上,Spring还为在框架内部存取 EJB、实现EJB的功能而提供了良好的支持。而且,如果利用Spring访问EJB所提供的服务,那么这些服务的具体实现可以在本地EJB、远程 EJB,或者POJO之间进行透明地切换,而无需改动任何一行客户端的程序代码。

     在本文中,我们着重讨论一下Spring访问、实现EJB的机制,特别是对于无状态会话bean(SLSB)的支持。

1.如何在Spring中访问EJB?
     在Java EE中,为了调用一个本地或者远程SLSB的方法,客户端必须首先通过JNDI查找获取一个(本地或者远程)EJB Home对象,而后通过这个 EJB Home对象的create()方法获取一个实际的(本地或者远程)EJB对象,从而调用此EJB对象的各种方法。
     为了避免底层代码的重复,许多EJB应用程序采用了Service Locator和Business Delegate设计模式,这比在客户端程序中使用很多JNDI查询要好很多,但其缺陷也是十分明显的,例如:
*  依赖Service Locator和Business Delegate singleton的程序代码通常是难以测试的。
*  若只使用Service Locator模式,而不使用Business Delegate,那么应用程序依旧必须调用一个EJB Home的craete()方法,并处理各种异常。因此,应用程序将与EJB的API与复杂编程模型紧密耦合在一起。
*  使用Business Delegate模式通常将造成大量的重复代码,仅仅为了调用EJB的同一个方法,开发人员必须编写许多程序。

      而通过Spring,则可以创建和使用在Spring内部配置好的代理,这个代理将扮演业务delegate的角色,开发人员无需编写另外一个 Service Locator和JNDI查询代码,也无需复制Business Delegate的方法调用,除非是在这些程序代码确实有其他有价值的内容。

     假设有一个需要使用本地EJB的web controller,我们将采用EJB的业务方法接口模式来实现,从而EJB的本地接口可以扩展一个非EJB的业务方法接口。我们将这个业务方法暂且称之为MyComponent,其定义类似于:


public interface MyComponent {
...
}

     使用业务方法接口模式的一个主要原因在于保证本地接口中的方法定义和接口实现bean的方法定义自动同步,另一原因是如果需要将该方法以POJO实现,那么这种转化将比较容易。当然,我们还需要实现本地home接口,并提供一个实现SessionBean和MyComponet业务方法接口的类。现在,为了将示例中的web controller与EJB实现挂钩,我们需要编写的唯一一段代码就是在这个controller中对外公开一个MyComponet对象的 setter,示例如下:

private MyComponent myComponent;
public void setMyComponent(MyComponent myComponent) {
this.myComponent = myComponent;
}

      然后,便可以在controller中的任何一个业务方法中调用这个myComponet实例。假设需要在Spring容器之外获取该 controller对象,我们可以在同一环境中配置一个LocalStatelessSessionProxyFactoryBean 实例作为EJB代理。这个代理的配置以及controller中myComponent属性的设置,均在Spring的配置文件定义,示例如下:

<bean id="myComponent"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
    <property name="jndiName" value="myComponent"/>
    <property name="businessInterface" value="com.ejbtest.MyComponent"/>
</bean>
<bean id="myController" class="com.ejbtest.myController">
    <property name="myComponent" ref="myComponent"/>
</bean>

     其中,通过myComponent的定义创建了一个EJB代理,而这个EJB将实现特定的业务方法接口。由于EJB的本地home在应用程序启动时就已经被缓存,所以这里只需要一个JNDI查询。每当这个EJB被调用时,EJB代理将调用本地EJB的classname()方法,并调用EJB提供的相应的业务方法。
这种EJB存取机制极大地简化了应用程序代码,web层代码(抑或其他EJB客户端)将不再依赖EJB的使用。如果我们想将EJB替换为POJO或者其他测试stub,只要把配置文件中的myComponent定义改动一下即可,Java程序依旧保持不变。而且,我们也不必再编写任何 JNDI查询代码,或者其他EJB的硬编码。


      实践表明,上述方法(包括对目标EJB的反射式调用)的运行开销是最小的。记住,我们并不想做任何针对EJB的细粒度调用,毕竟这涉及到Java应用服务器中EJB体系架构的成本开销。

       对于远程EJB的访问,本质上与访问本地EJB是相同的,除了需要 SimpleRemoteStatelessSessionProxyFactoryBean类。当然,无论是否使用Spring,远程调用的基本语义是适用的。当访问另外一台电脑的虚拟机中某个对象的方法时,这种调用的具体用法和失败处理必须以不同于本地访问的方式处理。

      Spring在EJB客户端支持方面,比非Spring方案具有更多优势。通常,EJB客户端在调用 本地或远程EJB时,很难做自由的前后切换。 这是因为远程接口方法必须抛出RemoteException,并且客户端程序必须处理此异常,但对于本地接口方法的调用则不需要这么做。若将处理本地 EJB的客户端程序用来处理远程EJB,那么必须作出修改以增加对远程异常情况的有效处理,同样,若将处理远程EJB的客户端程序用来处理本地EJB,也需要做很多无谓的工作来处理远程异常,或者将异常处理的程序代码删除。不过,当使用Spring远程EJB代理时,开发人员不必在业务逻辑方法接口和具体的EJB实现代码中声明抛出任何RemoteException,并且将有一个统一的远程接口(这个接口抛出RemoteException),并通过这个代理动态地分析客户端调用的是远程EJB还是本地EJB。 也即,客户端程序不需要再处理RemoteException,在调用EJB过程中抛出的任何RemoteException均将被重新以 RemoteAccessException类的形式抛出。于是,应用程序可以在本地EJB和远程EJB(甚至是POJO)间任意切换调用,而客户端代码无需关心这些后台的操作。当然,这个解决方案是可选的,用户可以根据自己的意愿在业务接口中声明抛出RemoteExceptions。

2.如何利用Spring实现EJB

      Spring还提供了若干易于使用的类,来帮助开发人员实现EJB。Spring鼓励开发人员将业务逻辑以POJO的形式实现,而将EJB的处理重点放在事务分界与远程调用。
       无论是无状态的会话bean,还是有状态的会话bean,抑或消息驱动的bean,其实现均需分别继承AbstractStatelessSessionBean, AbstractStatefulSessionBean, 和
AbstractMessageDrivenBean/AbstractJmsMessageDrivenBean。
      考虑一个无状态的会话bean的例子。业务接口定义如下:

public interface MyComponent {
   public void myMethod(...);
   ...
}
      我们用一个POJO实现该接口:

public class MyComponentImpl implements MyComponent {
public String myMethod(...) {
...
}
...
}


最后,定义无状态的会话bean:

public class MyComponentEJB extends AbstractStatelessSessionBean
implements MyComponent {

MyComponent myComp;

/**
* 从BeanFactory或者ApplicationContext获取POJO对象
* @参见 org.springframework.ejb.support.AbstractStatelessSessionBean的onEjbCreate()方法
*/
protected void onEjbCreate() throws CreateException {
myComp = (MyComponent) getBeanFactory().getBean(
ServicesConstants.CONTEXT_MYCOMP_ID);
}

// 具体的业务方法,以POJO实现
public String myMethod(...) {
return myComp.myMethod(...);
}
...
}

AbstractStatelessSessionBean缺省地创建并装载一个Spring IoC容器,这个容器对EJB也是有用处的,例如获取POJO服务对象。容器的装载过程由 BeanFactoryLocator的一个子类完成,缺省情况下使用ContextJndiBeanFactoryLocator来实现。 ContextJndiBeanFactoryLocator从一个资源文件创建ApplicationContext,资源文件的位置由JNDI环境变量指定,例如java:comp/env/ejb/BeanFactoryPath。如果需要更改BeanFactory /ApplicationContext装载策略,那么缺省的BeanFactoryLocator实现可以通过调用 setBeanFactoryLocator()方法来重载,这个方法可以在setSessionContext()或者EJB的构造函数中进行调用。
有状态的会话bean在其生命周期中存在休眠与激活的过程,若此有状态的会话bean使用了一个非序列化的容器实例,由于该bean无法被EJB容器保存,因此它必须从 ejbPassivate()和ejbActivate()分别手工地调用unloadBeanFactory()和loadBeanFactory() 方法。为了使用EJB,ContextJndiBeanFactoryLocator类需要装载一个ApplicationContext,这足以一般情况的需要。不过,若ApplicationContext装载很多bean,或者这些bean的初始化可能占用大量时间或内存资源的话,例如初始化 Hibernate的一个SessionFactory对象,这个解决方案就存在较大的问题,因为每一个EJB都将会有自己的一个copy。在此情况下,开发人员可以考虑重载缺省的ContextJndiBeanFactoryLocator,并使用BeanFactoryLocator的另一个变体,例如ContextSingletonBeanFactoryLocator类,这样便可以在多个EJB或客户端之间共享同一个容器。示例如下:

/**
* 重载缺省的BeanFactoryLocator实现
* @参见javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
*/
public void setSessionContext(SessionContext sessionContext) {
super.setSessionContext(sessionContext);
setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
setBeanFactoryLocatorKey(ServicesConstants.PRIMARY_CONTEXT_ID);
}

而后,创建一个bean定义文件,例如beanRefContext.xml,这个文件将定义EJB可能会用到的所有bean工厂。一般情况下,这个文件将只包含一个bean的定义,例如:

<beans>
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="businessApplicationContext.xml" />
</bean>
</beans>

其中 businessApplicationContext.xml文件包含了全部业务POJO对象的定义。ServicesConstants.PRIMARY_CONTEXT_ID则可以定义如下:

public static final String ServicesConstants.PRIMARY_CONTEXT_ID = "businessBeanFactory";


3.EJB与Spring究竟在何时进行集成?

     尽管Spring和EJB的目标都是为松散耦合的POJO提供企业级服务,但现在很多人都认为Spring+Hibernate的方案,可以充分替代 EJB,尤其EJB复杂的编程模型总是令人望而生畏,EJB的部署、运行效率亦总为人诟病。不过,EJB尤其是EJB 3.0在复杂信息系统构建方面,依旧有着Spring目前不能超越的特性。使用EJB 3.0的时候,基于标准的方法、注释的使用、以及与应用程序服务器的紧密集成,实现了厂商无关性,并提高开发效率。尤其是,EJB 3.0在面向事务处理的、尤其是异步通讯环境下的企业级应用方面,比Spring更具备优势。在处理fail-over、load balancing、distributed caching和state duplication、clustering等方面,开发人员在EJB 3.0的环境中不必关心这些问题(当然,在部署时需要考虑)。而在Spring中,需要使用声明式事务服务来管理Hibernate事务,开发人员必须在 XML配置文件中显式地配置Spring TransactionManager和Hibernate SessionFactory对象。Spring应用程序开发者必须显式地管理跨多个HTTP请求的事务。此外,要在Spring应用程序中使用群集服务也没有简单的途径。


       EJB与Spring本质上是相互竞争且相互学习的技术,很难说二者的集成是否能够充分彰显二者的优点,弥补彼此的缺陷。
分享到:
评论

相关推荐

    ejb spring

    ** ejb与Spring集成的优势** 1. **灵活性增强**:Spring的IoC容器允许更灵活地管理bean,而ejb则可以提供强大的事务管理和安全控制。结合两者,可以在 ejb 的强大功能基础上,利用Spring的轻量级特性,提高系统的...

    EJB&Spring;详细对比

    Spring 可以独立运行,也可以与其他应用服务器集成使用。它的配置主要依赖于XML文件,虽然这带来了较高的灵活性,但也增加了配置的复杂性和维护成本。随着版本的迭代,Spring也引入了注解支持,进一步提高了开发效率...

    spring集成ejb

    7. **测试集成**:在测试Spring集成EJB的应用时,可以使用Spring TestContext Framework,它可以方便地模拟EJB环境,便于单元测试和集成测试的执行。 8. **部署与运行**:集成后的应用需要部署在支持EJB的Java EE...

    weblogic8下ejb2.0与spring集成

    因本人现在工作中需要到ejb2.0,考虑到现在ejb2.0资料匮乏,故整理献上。具体步骤:把项目导出jar文件,在weblogic8中部署,运行Client.java即可。由于weblogic不支持jdk1.4以上版本,请使用jdk1.4编译

    spring与ejb的区别

    ### Spring与EJB3.0的关键区别及其优劣分析 #### 一、Spring框架概述 **1.1 引言** Spring作为一个广受欢迎的开源框架,最初被设计用于减轻企业级应用开发中的复杂性问题。它的一个显著特点在于模块化的分层架构...

    EJB3.0和Spring比较

    【EJB3.0与Spring比较】 EJB3.0和Spring是两种广泛使用的Java企业级应用程序开发框架,它们在很多方面有所不同,这些差异主要体现在以下几个关键点: 1. **厂商无关性(Vendor Independence)** - EJB3.0遵循开放...

    精通JSF基于EJB HibernateSpring整合天发与项目实践 书本源码

    4. Spring框架的IoC容器、AOP的实现、事务管理以及与JSF和EJB的集成。 5. 数据库连接池的配置和使用,例如C3P0或HikariCP。 6. MVC设计模式在JSF和Spring中的应用。 7. JPA(Java Persistence API)与Hibernate的...

    Hibernate+Spring+EJB+Ajax-关于这四种技术的详细讲解

    在IT行业中,Hibernate、Spring、EJB(Enterprise JavaBeans)和Ajax是四个非常重要的技术,它们各自在软件开发的不同方面发挥着关键作用。下面将分别详细介绍这些技术,并探讨它们之间的协同工作方式。 **...

    JSF基于EJB Hibernate Spring整合开发与项目

    ### JSF基于EJB Hibernate Spring整合开发与项目 #### 一、JSF基础知识 ##### 1.1 了解JSF JavaServer Faces (JSF) 是一个用于构建基于Web的应用程序的标准Java EE技术。它提供了丰富的组件库以及一套声明式的...

    精通JSF-基于EJB Hibernate Spring整合开发与项目实践-第14章代码

    在本章中,我们将深入探讨如何在Java企业级开发中集成和使用JavaScript Faces(JSF)、Enterprise JavaBeans(EJB)、Hibernate以及Spring框架。这些技术是构建高效、可扩展的企业级应用的重要工具,它们各自拥有...

    j2ee研究文集,ejb,spring

    与EJB中的MVC概念类似,Spring MVC将模型、视图和控制器分离,但更为轻便,且易于与其他Spring功能集成。 - Spring的IoC容器管理对象的生命周期和依赖关系,使得组件间的耦合度降低,提高了可测试性和可维护性。...

    EJB and Spring

    Spring可以通过其Enterprise JavaBeans模块(Spring EJB)与EJB进行集成,使得Spring的IoC容器可以管理EJB的生命周期,提供更灵活的配置和测试支持。EJB可以在Spring的应用上下文中声明为bean,从而利用Spring的特性...

    struts2 + ejb3 + spring 整合了

    在本文中,我们将探讨如何将三个流行的Java EE框架——Struts2、EJB3和Spring——集成在一起,形成一个强大的企业级应用。这个整合过程对于初学者来说可能会有些复杂,但通过逐步指导,我们将简化这一过程。我们使用...

    JPA学习笔记-EJB-06JPA+Spring使用经验

    ### JPA与Spring集成使用详解:基于EJB环境下的实践 #### 一、引言 在企业级应用开发中,Java Persistence API (JPA) 和 Spring 框架的结合使用已经成为一种趋势,它们共同提供了强大的数据访问能力,简化了数据库...

    spring with ejb3

    3. **测试友好**:Spring的测试支持(如Spring Test和Mockito)与EJB 3的测试工具(如EJBContainer)相结合,能更方便地进行单元测试和集成测试。 **EJB 3的核心概念** 1. **实体Bean(Entity Bean)**:代表持久化...

    精通JSF-基于EJB Hibernate Spring整合开发与项目实践-第16章代码

    Spring与JSF、EJB和Hibernate的集成,可以进一步优化应用的架构。例如,Spring的`@Transactional`注解可能被用来声明事务边界,确保数据的一致性。 在这个项目实践中,我们可以看到一系列的JSP文件,这些是JSF视...

    精通JSF-基于EJB Hibernate Spring整合开发与项目实践-第15章代码

    1. **JSF与Spring的集成**:如何在JSF应用中利用Spring进行依赖注入,以及如何在JSF的managed bean中使用Spring的bean。 2. **EJB与JSF的协同工作**:讲解如何在JSF页面上调用EJB服务,例如,通过会话Bean来处理...

    ejb3+spring+struts实现简单银行系统

    - Struts2与Spring的集成使得在业务逻辑处理上更加无缝,可以利用Spring的模型绑定和数据验证功能。 综合应用: - 通过Struts2的Action,用户请求会被映射到具体的业务处理方法,这些方法可能调用了Spring管理的...

    Java Jsp EJB Spring学习

    这些资源可能提供了进一步学习Java、JSP、EJB和Spring的资料,或者与这些技术相关的其他编程知识。 总的来说,掌握Java Jsp EJB Spring这些技术对于成为全面的Java EE开发者至关重要。每个技术都有其独特的功能和...

Global site tag (gtag.js) - Google Analytics