【Spring】Spring Framework Reference Documentation中文版26

来源:互联网 发布:修改vnc端口 编辑:程序博客网 时间:2024/05/16 14:19

29. Enterprise JavaBeans (EJB) integration

企业级JavaBean的集成

 

29.1 Introduction

介绍

 

As a lightweight container, Spring is often considered an EJB replacement. We do believe that for many if not most applications and use cases, Spring as a container, combined with its rich supporting functionality in the area of transactions, ORM and JDBC access, is a better choice than implementing equivalent functionality via an EJB container and EJBs.

作为一个轻量级的容器,spring经常作为一个EJB的替代品。我们相信对于大多数人如果大部分应用和用例,spring是作为一个容器,对于交易领域提供全方面的支持、ORMJDBC访问是一个较好的选择代替实现相同功能通过一个EJB容器和EJBs

 

However, it is important to note that using Spring does not prevent you from using EJBs. In fact, Spring makes it much easier to access EJBs and implement EJBs and functionality within them. Additionally, using Spring to access services provided by EJBs allows the implementation of those services to later transparently be switched between local EJB, remote EJB, or POJO (plain old Java object) variants, without the client code having to be changed.

然而,这是重要的有关使用避免在EJB中使用spring。实际上,spring使得访问EJB更加简单并且实现了EJB和他们的功能。此外,使用spring来访问EJB提供的服务允许实现这些服务在本地EJB和远程EJBPOJO之间进行切换,而不需要客户端做任何改变。

 

In this chapter, we look at how Spring can help you access and implement EJBs. Spring provides particular value when accessing stateless session beans (SLSBs), so well begin by discussing this.

在这个章节中,我们寻找spring如何可以帮助你来访问和实现EJBspring提供了特定的值当访问无状态的会话bean时,因此我们可以先讨论一下。

 

29.2 Accessing EJBs

访问EJBs

 

29.2.1 Concepts

内容

 

To invoke a method on a local or remote stateless session bean, client code must normally perform a JNDI lookup to obtain the (local or remote) EJB Home object, then use a 'create' method call on that object to obtain the actual (local or remote) EJB object. One or more methods are then invoked on the EJB.

为了调用一个本地或远程无状态的会话bean,客户端代码必须正常执行JNDI查找来获得(本地或远程)的EJBHomeobject,然后使用create方法调用对于获得的实际的(本地或远程)的EJBobjectEJB上的一个或多个方法会被调用。

 

To avoid repeated low-level code, many EJB applications use the Service Locator and Business Delegate patterns. These are better than spraying JNDI lookups throughout client code, but their usual implementations have significant disadvantages. For example:

为了避免重复的低级别代码,许多EJB应用使用服务定位器和业务代理模式。这比通过客户端来传播JNDI查找更好,但是他们通常实有一些明显的缺点。例如:

 

    Typically code using EJBs depends on Service Locator or Business Delegate singletons, making it hard to test.

通常使用EJB的代码依赖于服务定位器或业务代理单例,使得难于进行测试。

    In the case of the Service Locator pattern used without a Business Delegate, application code still ends up having to invoke the create() method on an EJB home, and deal with the resulting exceptions. Thus it remains tied to the EJB API and the complexity of the EJB programming model.

在服务定位模式而不使用服务代理时,应用代码依然需要调用EJBcreate方法并且处理结果中的异常。这和EJBAPI是绑定的并且是EJB编程模式中复杂性体现。

    Implementing the Business Delegate pattern typically results in significant code duplication, where we have to write numerous methods that simply call the same method on the EJB.

实现业务代理模式通常导致代码的重复,当我们需要多个简单的方法调用EJB中相同的方法。

 

The Spring approach is to allow the creation and use of proxy objects, normally configured inside a Spring container, which act as codeless business delegates. You do not need to write another Service Locator, another JNDI lookup, or duplicate methods in a hand-coded Business Delegate unless you are actually adding real value in such code.

spring的方式允许创建和使用代理object,正常配置在spring的容器中,不需要业务代理。你也不需要写另一个服务定位器、另一个JNDI查找或重复的方法在一个手写的业务代理除非你需要访问这样代码中的数据值。

 

29.2.2 Accessing local SLSBs

访问本地的SLSBs

 

Assume that we have a web controller that needs to use a local EJB. Well follow best practice and use the EJB Business Methods Interface pattern, so that the EJBs local interface extends a non EJB-specific business methods interface. Lets call this business methods interface MyComponent.

假设我们有一个web容器需要使用本地的EJB。我们将服务最好的方式并且使用EJB的业务方法接口模式,因此EJB的本地接口继承了一个非特定的EJB业务方法接口。让我们调用这个业务方法接口MyComponent

 

public interface MyComponent {

    ...

}

 

One of the main reasons to use the Business Methods Interface pattern is to ensure that synchronization between method signatures in local interface and bean implementation class is automatic. Another reason is that it later makes it much easier for us to switch to a POJO (plain old Java object) implementation of the service if it makes sense to do so. Of course well also need to implement the local home interface and provide an implementation class that implements SessionBean and the MyComponent business methods interface. Now the only Java coding well need to do to hook up our web tier controller to the EJB implementation is to expose a setter method of type MyComponent on the controller. This will save the reference as an instance variable in the controller:

其中一个使用业务方法接口模式的原因是保证方法在本地接口和实现类之间的同步是自动的。另一个原因是他使得对于切换POJO的服务实现是简单的。当然我们也需要实现本地的home接口并提供一个实现类来实现SessionBeanMyComponent的业务方法接口。现在我们只有Java代码需要绑定到我们的web层控制器对于EJB的实现暴露给控制器中MyComponent类型的set方法上。这会保存控制器中实例的引用。

 

private MyComponent myComponent;

 

public void setMyComponent(MyComponent myComponent) {

    this.myComponent = myComponent;

}

 

We can subsequently use this instance variable in any business method in the controller. Now assuming we are obtaining our controller object out of a Spring container, we can (in the same context) configure a LocalStatelessSessionProxyFactoryBean instance, which will be the EJB proxy object. The configuration of the proxy, and setting of the myComponent property of the controller is done with a configuration entry such as:

我们可以随后使用这个实例变来在控制器中任何的业务方法中。现在假设我们获得了控制器objectspring的容器之外,我们可以(在同一个上下文中)配置一个LocalStatelessSessionProxyFactoryBean实例,是EJB的代理object。代理的配置和控制器中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>

 

Theres a lot of work happening behind the scenes, courtesy of the Spring AOP framework, although you arent forced to work with AOP concepts to enjoy the results. The myComponent bean definition creates a proxy for the EJB, which implements the business method interface. The EJB local home is cached on startup, so theres only a single JNDI lookup. Each time the EJB is invoked, the proxy invokes the classname method on the local EJB and invokes the corresponding business method on the EJB.

在这个场景的背后有复杂的处理逻辑,包括springAOP框架的使用,尽管你没有强制使用AOP切面来处理结果。myComponentbean的定义创建了一个代理为EJB并且实现了业务方法接口。EJB的本地home在启动时被缓存因此他是一个单一的JNDI查找。对于每次EJB的调用,代理调用类名方法在本地的EJB上并且调用相应的EJB上的业务方法。

 

The myController bean definition sets the myComponent property of the controller class to the EJB proxy.

myControllerbean定义设置了EJB代理中控制器里面的myComponent属性。

 

Alternatively (and preferably in case of many such proxy definitions), consider using the <jee:local-slsb> configuration element in Springs "jee" namespace:

作为替代(并且由于大部分这样代理定义的原因),考虑使用<jee:local-slsb>配置元素在spring的“jee”命名空间:

 

<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>

 

This EJB access mechanism delivers huge simplification of application code: the web tier code (or other EJB client code) has no dependence on the use of EJB. If we want to replace this EJB reference with a POJO or a mock object or other test stub, we could simply change the myComponent bean definition without changing a line of Java code. Additionally, we havent had to write a single line of JNDI lookup or other EJB plumbing code as part of our application.

EJB访问策略需要复杂的应用代码配置:web绑定代码(或其他EJB的客户端代码)没有依赖EJB的使用。如果我们希望代替EJB的引用有关POJO或模拟object或其他测试部分,我们将简单的改变myComponentbean的定义而不需要改变Java代码。此外,我们不需要写一行JNDI查找或其他EJB的代码作为应用的一部分。

 

Benchmarks and experience in real applications indicate that the performance overhead of this approach (which involves reflective invocation of the target EJB) is minimal, and is typically undetectable in typical use. Remember that we dont want to make fine-grained calls to EJBs anyway, as theres a cost associated with the EJB infrastructure in the application server.

在实际应用中的标准和经验知识了这种方式的行为(调用相应的代码对于目标EJB)是最小化的,并且在典型的使用中是不会被发现的。记住我们不希望调用EJB,在应用服务器中连接EJB的架构是非常复杂的。

 

There is one caveat with regards to the JNDI lookup. In a bean container, this class is normally best used as a singleton (there simply is no reason to make it a prototype). However, if that bean container pre-instantiates singletons (as do the various XML ApplicationContext variants) you may have a problem if the bean container is loaded before the EJB container loads the target EJB. That is because the JNDI lookup will be performed in the init() method of this class and then cached, but the EJB will not have been bound at the target location yet. The solution is to not pre-instantiate this factory object, but allow it to be created on first use. In the XML containers, this is controlled via the lazy-init attribute.

这是对于JNDI调用的终止。在一个bean的容器中,这个类通常被使用以单例的模式(可以设置为prototype模式)。然而,如果bean容器提前初始化的单例(作为不同的xml的应用变量)你可以有疑问如果bean容器在EJB容器加载EJB之前被加载。这是因为JNDI查找将被执行在这个类的init方法中并且被缓存,EJB将不会绑定到目标的位置。对于工厂object的提前实例化,但是允许在首次使用时创建。在xml容器中,这是由延迟加载属性来控制的。

 

Although this will not be of interest to the majority of Spring users, those doing programmatic AOP work with EJBs may want to look at LocalSlsbInvokerInterceptor.

尽管对于主流的spring用户可能对此不感兴趣,这些编程AOP使用EJB需要查看LocalSlsbInvokerInterceptor

 

29.2.3 Accessing remote SLSBs

访问远程的SLSBs

 

Accessing remote EJBs is essentially identical to accessing local EJBs, except that the SimpleRemoteStatelessSessionProxyFactoryBean or <jee:remote-slsb> configuration element is used. Of course, with or without Spring, remote invocation semantics apply; a call to a method on an object in another VM in another computer does sometimes have to be treated differently in terms of usage scenarios and failure handling.

访问远程的EJB是有必要的对于访问本地的EJB,期望SimpleRemoteStatelessSessionProxyFactoryBean<jee:remote-slsb>配置元素被使用。当然,使用或者放弃spring,远程调用语义都是适用的,调用一个远程访问或object在另一个VM在不同的机器中需要不同对待用于场景和错误的处理。

 

Springs EJB client support adds one more advantage over the non-Spring approach. Normally it is problematic for EJB client code to be easily switched back and forth between calling EJBs locally or remotely. This is because the remote interface methods must declare that they throw RemoteException, and client code must deal with this, while the local interface methods dont. Client code written for local EJBs which needs to be moved to remote EJBs typically has to be modified to add handling for the remote exceptions, and client code written for remote EJBs which needs to be moved to local EJBs, can either stay the same but do a lot of unnecessary handling of remote exceptions, or needs to be modified to remove that code. With the Spring remote EJB proxy, you can instead not declare any thrown RemoteException in your Business Method Interface and implementing EJB code, have a remote interface which is identical except that it does throw RemoteException, and rely on the proxy to dynamically treat the two interfaces as if they were the same. That is, client code does not have to deal with the checked RemoteException class. Any actual RemoteException that is thrown during the EJB invocation will be re-thrown as the non-checked RemoteAccessException class, which is a subclass of RuntimeException. The target service can then be switched at will between a local EJB or remote EJB (or even plain Java object) implementation, without the client code knowing or caring. Of course, this is optional; there is nothing stopping you from declaring RemoteExceptions in your business interface.

springEJB的客户端支持非spring方式的额外的优点。正常的对于EJB代码的编程可以简单的切换到调用本地或远程的EJB中。这是因为远程接口方法必须定义并且抛出RemoteException,并且客户端代码需要处理这个异常,本地接口方法则不需要。客户端代码用于本地的JEB需要通常转换为远程的EJB需要修改和增加处理远程异常的代码,客户端代码用于远程的EJB转换为本地的EJB需要保持一致并且不需要处理远程异常或需要修改代码。在spring远程EJB代理中,你可以代替定义任何抛出的RemoteException在你的业务方法接口中并且实现EJB代码,有一个远程接口是完全相同的但是不会抛出RemoteException,并且依赖于动态的代理来处理两个接口如果她们是相同的话。这是因为客户端代码不需要处理检查的RemoteException类。任何实际的RemoteException被抛出在EJB的调用期间将被重新抛出作为一个非检查的RemoteAccessException类,是RuntimeException的一个子类。目标服务可以在本地EJB或远程EJB之间进行切换(或普通的object)实现,而不需要客户端代码知道。当然这是可选的,不需要在你的业务接口中定义RemoteExceptions

 

29.2.4 Accessing EJB 2.x SLSBs versus EJB 3 SLSBs

访问EJB 2.x SLSBsEJB 3 SLSBs

 

Accessing EJB 2.x Session Beans and EJB 3 Session Beans via Spring is largely transparent. Springs EJB accessors, including the <jee:local-slsb> and <jee:remote-slsb> facilities, transparently adapt to the actual component at runtime. They handle a home interface if found (EJB 2.x style), or perform straight component invocations if no home interface is available (EJB 3 style).

访问EJB2.x的会话beanEJB3的会话bean通过spring是透明化的。springEJB访问包括<jee:local-slsb><jee:remote-slsb>设施,显然适应于实际的运行时组件。他们处理一个home接口如果发现(EJB2.x的风格),或执行组件调用若没哟home接口可用。(EJB3的风格)

 

Note: For EJB 3 Session Beans, you could effectively use a JndiObjectFactoryBean / <jee:jndi-lookup> as well, since fully usable component references are exposed for plain JNDI lookups there. Defining explicit <jee:local-slsb> / <jee:remote-slsb> lookups simply provides consistent and more explicit EJB access configuration.

注意:对于EJB3的会话bean,你可以有效的使用JndiObjectFactoryBean<jee:jndi-lookup>,因为有用的组件引用被暴露作为普通的JNDI调用。定义明确的<jee:local-slsb><jee:remote-slsb>查找简单的提供一致的或更加明确的EJB访问配置。

 

29.3 Using Springs EJB implementation support classes

使用springEJB实现支持类

 

29.3.1 EJB 3 injection interceptor

EJB3的注入拦截器

 

For EJB 3 Session Beans and Message-Driven Beans, Spring provides a convenient interceptor that resolves Springs @Autowired annotation in the EJB component class: org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor. This interceptor can be applied through an @Interceptors annotation in the EJB component class, or through an interceptor-binding XML element in the EJB deployment descriptor.

对于EJB3的会话Bean和消息驱动beanspring提供了一个方便的拦截器来解决spring@Autowired注解在EJB组件类中:org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor。拦截器可以简单的应用通过@Interceptors注解在EJB组件类中或通过一个interceptor-bindingxml元素在EJB部署的描述符中。

 

@Stateless

@Interceptors(SpringBeanAutowiringInterceptor.class)

public class MyFacadeEJB implements MyFacadeLocal {

 

    // automatically injected with a matching Spring bean

    @Autowired

    private MyComponent myComp;

 

    // for business method, delegate to POJO service impl.

    public String myFacadeMethod(...) {

        return myComp.myMethod(...);

    }

 

    ...

 

}

 

SpringBeanAutowiringInterceptor by default obtains target beans from a ContextSingletonBeanFactoryLocator, with the context defined in a bean definition file named beanRefContext.xml. By default, a single context definition is expected, which is obtained by type rather than by name. However, if you need to choose between multiple context definitions, a specific locator key is required. The locator key (i.e. the name of the context definition in beanRefContext.xml) can be explicitly specified either through overriding the getBeanFactoryLocatorKey method in a custom SpringBeanAutowiringInterceptor subclass.

SpringBeanAutowiringInterceptor默认获得一个目标bean来自ContextSingletonBeanFactoryLocator,上下文定义在bean的定义中名字为beanRefContext.xml。默认的,一个单独的上下文定义是被期望的,通过类型来获得而不是通过名字,如果你需要选择多个上下文定义,一个特定的定位关键字是必须的。定位关键字(例如上下文定义的名字在beanRefContext.xml文件中)可以明确的指定通过覆盖SpringBeanAutowiringInterceptor子类中的getBeanFactoryLocatorKey方法。

 

Alternatively, consider overriding SpringBeanAutowiringInterceptors `getBeanFactory method, e.g. obtaining a shared ApplicationContext from a custom holder class.

作为替代,考虑覆盖SpringBeanAutowiringInterceptorgetBeanFactory方法,例如,获得一个共享的ApplicationContext来自一个自定义的处理器类。

 

 

阅读全文
0 0
原创粉丝点击