EJB3~无状态会话bean

来源:互联网 发布:网络转账骗局怎么处理 编辑:程序博客网 时间:2024/05/01 12:24

无状态会话bean用于完成在单个方法的生命周期内的操作。无状态bean可以实现许多业务操作,但是每个方法都不能假定任何其他的方法会在它之前调用。后半句的意思是现在的你可能不是刚才的你,明天的你可也能不是今天的你,这个时候你就叫做“无状态你”。

上面的阐述听起来像是无状态的bean的一个局限,好像每次再见就像永别似的。但是这是迄今为止业务服务最常见的形式,就像去饭店吃饭,点菜的服务员与给你上菜的服务员是不是同一个这不是我们所关心的。无状态回话bean不同于适合在对话中积累状态(如零售应用程序的购物车)的有状态会话bean,无状态回话bean旨在非常有效的执行独立操作。无状态会话bean这样设计的目的也是考虑到服务器忍受不了大量客户端的时候对资源的占用。

会话bean定义分为如下两个部分:

l  零个或多个业务接口,定义了一个客户端在bean上可以调用的方法。当没有定义接口时,bean的实现类的公共方法集合形成了一个逻辑客户端接口。

l  实现这些接口的类,称之为bean类,采用@Stateless注解进行标记。

大多数会话bean有一个业务接口,但是对会话bean可以向其客户端公开的接口数量是没有限制。当服务器遇到@Stateless注解时,它会知道把该bean当做一个会话bean。它将在EJB容器中配置这个bean,使得应用程序的其他组件可以使用它。

下面的这个EJB版本的Hello World例子中包含了一个业务接口。在此示例中包含了一个单一的方法。没有注解或者父接口来指明这是一个业务接口,和一般的类实现接口看起来是一模一样的。当会话bean实现它时,将会自动把它视为一个本地业务接口,意味着只有在同一个应用程序服务器上的客户端能够访问它。为了强调一个接口是本地业务接口,可以选择把@Local注解添加到该接口上。

  1. public interface HelloService {  
  2.     public String sayHello(String name);  
  3. }  

现在考虑接口的实现。下面的代码展示的是一个实现了上面接口的常规Java类 。这个类唯一特别的是@Stateless注解,标记它是一个无状态会话bean。业务方法实现上没有任何特殊的限制或要求,它恰好是一个EJB的常规类。

  1. @Stateless  
  2. public class HelloServiceBean implements HelloService {  
  3.     public String sayHello(String name) {  
  4.         return "Hello, "  + name;  
  5.     }  
  6. }  

关于无接口视图

在EJB3.1中引入无接口视图(no-interface-view),它支持本地会话bean可以没有实现接口。这使得定义一个本地会话bean以及访问这个本地会话bean更加简单。如下面代码所示使用无接口视图定义上面代码中相同的HelloServiceBean,开发人员只需创建实现类,无需实现任何业务接口:

  1. @Stateless  
  2. public class HelloServiceBean {  
  3.     public String sayHello(String name) {  
  4.         return "Hello, "  + name;  
  5.     }  
  6. }  

会话bean的逻辑接口包含了它的公共方法,在本例中是sayHello()方法。客户端把HelloServiceBean类当做接口一样使用,不必考虑任何非公开的方法或实现的详细信息。可以想象服务器内部向客户端提供了一个代理接口,这个代理覆盖业务方法以提供标准的容器服务,客户端将与这个代理进行交互。

无接口视图的优点之一是简单。它不需要实现一个冗余的业务接口,并进一步使得EJB看起来像是常规JavaBean类。然而,由于无接口视图仅适用于本地回话bean,本例中采用传统样式的独立接口,从而保证无状态和有状态会话bean一致。

对于无状态会话bean类的定义只需要注意两点。第一是它需要一个无参数的构造函数,但是当没有其他的构造函数时,编译器通常会自动生成此构造函数。第二是不应该使用静态字段,这主要是因为bean的重新部署问题。

许多EJB容器创建一个无状态会话bean的实例池,然后选择任意的一个实例以服务每个客户端请求。因为这不能保证调用之间将使用相同的状态,所以不能认为点菜的服务员与给你上菜的服务员一定是同一个人。

与用于应用程序代码的常规Java类不同,服务器管理无状态会话bean的声明周期它在两个方面影响了一个bean的实现。

首先,服务器决定了创建和删除bean实例的时间。应用程序不会控制何时或者甚至创建多少特定的无状态会话bean实例,或者它们将存活多久。

第二,服务器必须在构建之后,但是在调用bean的业务逻辑之前,初始化bean服务。同样,该bean可能必须在使用业务方法之前获得可用的资源,如JDBC数据源。然而,为了使得bean获取资源,服务器必须首先完成初始化bean服务。这限制了类的构造函数的用处,因为直到服务器完成初始化后,bean才可以访问资源。

为了允许服务器和bean实现它们的初始化要求,EJB支持生命周期的回调方法,可以由服务器在bean生命周期的不同点调用。对于无状态会话bean,有两个生命周期回调:PostConstruct和PreDestroy。一旦服务器已为bean完成了初始化所有的容器的服务,它将会调用PostConstruct回调。实际上,它将替换构造函数成为初始化逻辑的位置所在,因为只有在这里才能保证容器服务是可用的。在服务器释放bean实例到垃圾回收之前,立即调用PreDestroy回调。在PreDestroy中释放由需要显示关闭的PostConstruct所获得的任何资源

下面的代码显示了一个无状态会话bean,它在PostConstruct回调中获取了一个logger的实例的引用。Bean之多有一个PostCons回调方法,由@PostConstruct标记注解所标识。同样,由@PreDestroy注解标识PreDestroy回调

迄今为止,我们只讨论了使用一个本地业务接口的会话bean。在这种情况下,本地意味着只能由运行在同一个应用程序服务器实例的JavaEE组件声明会话bean的依赖性。例如,远程客户端不可能通过本地接口使用会话bean。

为了容纳远程客户端,会话bean可以采用@Remote注解来标记它们的业务接口,以声明它是远程可用的。下面代码演示了前面所示的HelloService接口的远程版本语法。标记一个接口为远程的相当于使其扩展Java.rmi.Remote接口。客户端获取的bean的引用不再是服务器上的一个本地引用,而是远程方法调用(RMI)的存根(stub),从而可以跨网络调用会话bean的操作。在bean类之上使用远程接口无需特别的支持。

(代码)

把接口变为远程的会影响性能以及如何处理传递给业务方法的参数。远程业务接口可以在本地运行的服务器中使用,但是如果方法调用是通过RMI层进行路由,那么这样做可能仍会导致网络开销。远程接口之上的方法的参数也是按值传递,而不是按引用传递。这意味着即时客户端对会话bean而言是本地,也需要序列化参数。为本地客户端提供本地接口通常是更好的方法。本地接口保存常规java方法调用的语义,避免了与网络和RMI相关的开销。

注意:

许多应用程序服务器提供选项以提高远程接口在本地使用时的性能,其中可能包括能够禁用方法参数的序列化护着坑农完全避开RMI。当在应用程序代码中使用这些功能时要谨慎,以为它们对于不同的应用服务器是不可移



1 0
原创粉丝点击