循速渐进学用Session Bean 1

创建无状态的Session Bean

  从编程的角度看,创建无状态的Session Bean和创建有状态的是一样简单的。除了在配置工具里修改一个设置外,仅有的一点不同是在bean的初始设计阶段,无状态的Session Bean并不记得方法调用之间的任何东西,bean需要的任何消息都必须由客户端获得。虽然无状态的Session Bean并不记得面向session的数据,不过可以在一个无状态的session bean中存放数据,只是不能存放与客户端相关的数据。

  在HelloWorldSession的例子中,该bean在方法调用之间仍记得一个问候的字符串。例如,你调用setGreeting来修改欢迎词,当你调用getGreeting时,该session会记得保存的欢迎词。

  列表6.5“Hello World”session bean Remote 接口(无状态版本)

  Listing 6.5 Source Code for StatelessHello.java
package usingj2ee.hello;
  import java.rmi.*;
import javax.ejb.*;
  /** Defines the methods you can call on a StatelessHello object */
  public interface StatelessHello extends EJBObject
{
  /** Returns a greeting for the named object */
public String greet(String thingToGreet) throws RemoteException;
  }

  在这个例子中,Remote接口仅提供了一个greet方法,该方法接收一个参数并且返回一个欢迎词。例如,如果传送“World”参数给greet,greet方法将返回“Hello World!”。

  列表6.6展示了StatelessHello bean的Home接口。

  Listing 6.6 Source Code for StatelessHelloHome.java
package usingj2ee.hello;
  import java.rmi.*;
import javax.ejb.*;
  /** Defines the methods for creating a StatelessHelloWorld */
  public interface StatelessHelloHome extends EJBHome
{
  /** Creates a StatelessHello session bean. A stateless session bean
can't have a create method that takes parameters. */
public StatelessHello create() throws RemoteException, CreateException;
  }

无状态的session bean仅拥有一个create方法,而且该方法不能接受任何参数。这看起来有些奇怪,不过如果考虑到无状态session bean的含义你就会明白了。这种bean不能记住某个客户的任何信息,实际上,为了性能上的原因,容器也许会不时地让不同的session处理某个客户的方法调用。由于session并不需要记住某个客户的信息,因此使用另一个bean来处理负载并不会带来任何问题。

  如果bean的create方法接受任何的参数,session bean实例之间的行为将会有所不同,因为你为create方法提供不同的值。

  实现无状态session bean与有状态的session bean是一样简单的。列表7中的是StatelessHelloImpl类,它实现了Remote和Home接口。

  Listing 6.7 Source Code for StatelessHelloImpl.java
package usingj2ee.hello;
  import java.rmi.*;
import java.util.*;
import javax.ejb.*;
  /** The implementation class for the StatelessHello bean */
  public class StatelessHelloImpl implements SessionBean
{
/** The session context provided by the EJB container. A session bean must
hold on to the context it is given. */
private SessionContext context;
  /** An EJB must have a public, parameterless constructor */
  public StatelessHelloImpl()
{
}
  /** Called by the EJB container to set this session's context */
  public void setSessionContext(SessionContext aContext)
{
context = aContext;
}
  /** Called by the EJB container when a client calls the create() method in
the Home interface */
public void ejbCreate()
throws CreateException
{
}
  /** Called by the EJB container to wake this session bean up after it
has been put to sleep with the ejbPassivate method. */
  public void ejbActivate()
{
}
  /** Called by the EJB container to tell this session bean that it is being
suspended from use (it's being put to sleep). */
  public void ejbPassivate()
{
}
  /** Called by the EJB container to tell this session bean that it has been
removed, either because the client invoked the remove() method or the
container has timed the session out. */
  public void ejbRemove()
{
}
  /** Returns a greeting for the named object */
  public String greet(String thingToGreet)
{
return "Hello "+thingToGreet+"!";
}
}

  注意:

 配置无状态session bean的过程和有状态bean几乎是一样的。只要确认已经配置bean为无状态的,可能需要在Stateless的选项旁打上一个勾或者确认去除Manages Conversational State旁的选项。

 

orderPlacementBean.submitOrder(this);

  这里的问题是submitOrder方法的声明也许如下所示:

public void submitOrder(ShoppingCart cart) throws RemoteException;

  这里有一个问题,因为ShoppingCart是session bean的Remote接口(至少这个例子中是),this变量将指向一个ShoppingCartImpl对象,不过该对象并没有实现ShoppingCart的接口。使用EJB时,这些区别将会令你感到迷惑。一个EJB实际上有两部分:Remote接口和实现。实现并不是一个远程的对象,也就是说,它并不实现Remote接口。实际上,在许多的EJB实现中,Remote接口调用容器上的方法,而容器就调用实现上的方法,就好象调用标准方法一样,例如ejbCreate和ejbRemove。

  调用submitOrder的正确方式是

orderPlacementBean.submitOrder((ShoppingCart) sessionContext.getEJBObject());

  当然,对于这段代码,它是假定setSessionContext方法是这样的:

public void setSessionContext(SessionContext aContext)
{
sessionContext = aContext;
}

  即使在你的bean中并不需要session context,保留它也是一个好主意。它仅需要几行代码,这样就可以认为一直存在这个方法。

  提示

  如果让保留session context成为一个标准,那么还需要标准化对context的访问。也就是说,为context选择一个标准化的变量名字,或者创建一个标准的方法,例如getSessionContext。

  ejbRemove

  EJB容器调用session bean的ejbRemove方法来告诉该bean的服务将要停止。这时bean应该要清除它保留的全部资源。

  提示

  如果bean在setSessionContext方法中建立了一个数据库连接,那么需要在ejbRemove方法中关闭该连接。如果你创建了任何的session bean,也可在ejbRemove方法中移除,同时将定位的Home接口设置为null。

  ejbPassivate 和 ejbActivate

  Enterprise JavaBeans规范中,提供了各种方法让EJB容器实现负载均衡以及其它各种和性能相关的工作。Passivation/Activation就是这样一个操作,它与计算机管理内存的方式是类似的。

  ejbPassivate 和 ejbActivate 方法允许一个EJB容器来使用内存交换技术。在某个时刻,如果EJB容器觉得内存中的许多bean都有一段时间没人访问了,它可能选择将其中的bean存储到磁盘上。也就是说EJB容器使用对象串行化不常用的bean并存储在某个文件中。这个过程在EJB中被称为passivation。当一个客户想访问一个passivated的bean时,EJB容器通过将它由磁盘中读出,从而再次激活该bean。

  ejbPassivate和ejbActivate方法帮助EJB容器解决了一个问题--你不能串行化某些“活动的”操作系统资源,例如网络连接等。由于大部分的数据库连接都需要一个网络连接,这就意味着不能串行化数据库连接。

  如果你在setSessionContext方法中建立了一个数据库连接,在EJB容器需要passivate该session bean时,你必须对该连接做一些处理,通常是你应该关闭连接并且设置该连接变量为null。当EJB容器调用ejbActivate方法时,再重新建立连接。

  提示

  不要错误地认为在session bean首次创建时会调用ejbActivate。ejbActivate方法仅在ejbPassivate方法被调用后执行。

  ******************图6.7 *****************

  Sessin Bean的更多细节问题

  现在我们对session bean的结构及如何实现已经有了一个认识,为了在设计和开发session bean时更有效率,还需要知道一些更多的细节问题。

  SessionBean的接口

  每一个session bean都必须实现SessionBean接口,它包含有4个方法,EJB容器使用这些方法来管理session bean。

  setSessionContext

  SessionContext对象包含有session bean运行环境的信息,并包含到Home接口的引用,以及自身的引用,事务信息和某个方法调用者的标识符。

  对于每个session bean,setSessionContext方法都会被调用一次,这也bean初始化的一部分。在调用setSessionContext后,该bean就成为EJB容器的一个活动部分,并且一直保持活动状态,直到调用ejbRemove为止。

  提示

  setSessionContext方法是放入初始代码的好地方,在这里可以创建数据库连接或者查找另一个bean的Home接口。

  在setSessionContext接口的方法中,getEJBObject可能是最常调用的一个。有时EJB必须传送自己到另一个方法中。例如,假定你拥有一个ShoppingCart bean,包含有顾客想要订购的商品信息。此外,还拥有一个OrderPlacement session bean负责接收ShoppingCart的内容并将它输入定单系统中。当公司希望将现有的定单系统移植到另一个平台上,例如由大型机转移到EJB服务器时,只需要修改OrderPlacement bean而无需理会shopping cart。ShoppingCart bean管理用户想要购买的东西,OrderPlacement bean负责放置定单。

  现在,当ShoppingCart bean需要调用OrderPlacement bean时,它只是使用this关键字来传送自己:

  列表6.8展示的是一个客户测试无状态session bean的代码

  Listing 6.8 Source Code for TestStatelessHello.java
package usingj2ee.hello;
  import java.util.*;
import javax.naming.*;
import javax.rmi.*;
public class TestStatelessHello
{
public static void main(String[] args)
{
try
{
  /** Creates a JNDI naming context for location objects */
Context context = new InitialContext();
  /** Asks the context to locate an object named "HelloWorld" and expects the
object to implement the HelloWorldSessionHome interface */
  StatelessHelloHome home = (StatelessHelloHome)
PortableRemoteObject.narrow(
context.lookup("StatelessHello"),
StatelessHelloHome.class);
/** Asks the Home interface to create a new session bean */
StatelessHello session = (StatelessHello) home.create();
  System.out.println(session.greet("World"));
System.out.println(session.greet("Solar System"));
System.out.println(session.greet("Universe"));
  /** Destroy this session */
session.remove();
}
catch (Exception exc)
{
exc.printStackTrace();
}
}
}

  图6.7展示了TestStatelessHello程序的输出

你可能感兴趣的:(循速渐进学用Session Bean 1)