Spring之Enterprise JavaBeans (EJB) integration(EJB集成)

22.1 介绍html

做为一个轻量级容器,Spring被认为是EJB的替代品。咱们确实相信,若是没有太多的应用和使用状况下,Spring做为一个容器,结合其在事物,ORM和数据访问方面丰富的支持功能,这比使用EJB和EJB容器完成同等功能上是一个更好的选择。java


然而,重要的一点是使用Spring就不是不使用EJB了。实际上,Spring使得访问EJBs和实现EJBs和内部功能上更加容易。另外,使用Spring访问由EJBs提供的业务容许那些业务的实现类以后轻松地在本地EJB,远程EJB,或者POJO变量之间转换,而不须要改变客户端的代码。web


在这一章中,将看到Spring如何帮助你访问和实现EJBs。Spring提供了专门的value来访问无状态的会话beans(SLSBs)。spring


22.2 访问EJBs编程


22.2.1 概念缓存


为调用本地或远程无状态会话bean的方法,客户端代码必须通常地执行一个JNDI查找来获取本地或远程的EJB的主项目,稍后在那个对象上调用create方法来获取真正的远程或本地的EJB对象。这里EJB会调用一个或更多的方法。服务器


为避免重复的低级代码,许多EJB应用程序采用service Locator(服务定位器)和业务委托模式。这些都比经过客户端代码执行JNDI查询好得多,可是了它们通常的实现还有明显的缺陷。例如:框架

  • 通常地使用EJBs依赖服务定位或业务委托单例,使得很难测试。
  • 在使用服务定位而不使用业务委托的状况下,应用程序代码仍旧以调用EJB的create()方法结束并处理致使的异常。它仍旧保留了与EJB API耦合而且保留了复杂的EJB 编程模式
  • 实现业务委托模式通常地致使了明显的代码重复,这里咱们得写许多方法,这些仅仅调用EJB相同的一个方法。

Spring的方式是容许代理对象的建立和使用,通常在Spring容器的内部配置,能够是无代码的业务委托。你不须要写另外一个服务定位器,另外一个JNDI查找,或者一个手编程序的业务委托的重复方法,除非你在这样的代码中确实须要添加实际的值。less


22.2.2 访问本地SLSBs异步

假设咱们有一个web控制器,其须要使用一个本地的EJB。咱们将按照最好的实践并使用EJB业务方法接口模式,这样EJB的本地接口继承了一个非EJB-指定的业务方法接口。称这个业务方法接口为MyComponent。

public interface MyComponent {
    ...
}



使用业务方法接口模式的主要缘由之一是确保本地接口和bean实现类之间的异步是原子的。另外一个缘由是稍后使得咱们转换成业务的一个POJO实现更加容器,若是应用程序对此很关注的话。固然了咱们也须要实现本地home接口而且提供一个实现类实现SessionBean和MyComponent业务方法接口。如今咱们须要作的Java编码工做(将web层控制器链接到EJB的实现类)是暴露控制器MyComponent类型的一个setter方法。这样将节省一个引用,其在控制器内做为一个实例变量。


private MyComponent myComponent;

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

咱们能够随后在这个控制器的任何业务方法中使用这个实例变量。如今假设咱们从一个Spring容器的外部获取了咱们的控制器对象,在同一上下文中,咱们能够配置一个LocalStatelessSessionProxyFactoryBean实例,这是一个EJB代理对象。这个代理的配置,和这个控制器的myComponent属性的设置,在一个配置条目中处理。

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

<bean id="myController" class="com.mycom.myController">
    <property name="myComponent" ref="myComponent"/>
</bean>

借助Spring AOP框架,这个场景幕后有许多事情发生,虽然你能够不强制使用AOP概念来享受你要的结果。myComponent bean定义建立了EJB的代理,其实现了业务方法接口。EJB本地home在启动的时候缓存,因此仅有单一的JNDI查询。每次调用EJB时,代理调用本地EJB的classname方法并调用EJB对应的业务方法。


myController bean定义为EJB代理设置了控制器类myComponent属性。


另外,若是有不少这样代理定义的状况下,考虑在Spring的"jee"命名空间内使用 <jee:local-slsb>配置元素。

<jee:local-slsb id="myComponent" jndi-name="ejb/myBean"
        business-interface="com.mycom.MyComponent"/>

<bean id="myController" class="com.mycom.myController">
    <property name="myComponent" ref="myComponent"/>
</bean>


EJB访问机制简化了应用程序代码:web层代码(其余EJB客户端)不依赖EJB的使用。若是咱们想使用一个POJO,或者一个虚拟对象或者其余的测试存根代替这个EJB引用,咱们只须要简单地改变myComponent bean定义,而不须要改变一行Java 代码。此外,咱们没必要去写一个单行的JNDI查询或者其余的EJB垂直代码,来做为咱们应用程序的部分。



在真实应用程序中的基准测试程序和经验指明这种方式的执行开销(涉及到目标EJB的反射调用)是最低的,并在通常使用中是没法察觉的。记住,咱们不想作任何对于EJBs的细粒度调用,由于在应用程序服务器关联EJB底层中会增长开销。


在JNDI查询中有一个警告,在一个bean容器中,这个类通常以单例使用(这里没有理由设置为prototype)。然而,若是那个bean预先实例化为单例(犹如作不一样的XML ApplicationContext 变量),若是bean容器在EJB容器加载目标EJB以前,你可能会遇到问题。这是由于JNDI查询将在这个类的init()方法中执行并在以后缓存,可是了EJB尚未绑定到目标位置上。虽然这个解决方案没有预先实例化这个工厂对象,可是容许在第一次使用的时候建立。在这个XML容器中,经过lazy-init属性控制。


虽然这个不是Spring使用者最感兴趣的地方,但那些使用EJBs作程序化AOP编程可能想看看LocalSlsbInvokerInterceptor。