从编程的角度看,创建无状态的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 import java.rmi.*; /** defines the methods you can call on a statelesshello object */ public interface statelesshello extends ejbobject /** returns a greeting for the named object */ } |
在这个例子中,remote接口仅提供了一个greet方法,该方法接收一个参数并且返回一个欢迎词。例如,如果传送“world”参数给greet,greet方法将返回“hello world!”。
列表6.6展示了statelesshello bean的home接口。
listing 6.6 source code for statelesshellohome.java import java.rmi.*; /** defines the methods for creating a statelesshelloworld */ public interface statelesshellohome extends ejbhome /** creates a statelesshello session bean. a stateless session bean } |
无状态的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 import java.rmi.*; /** the implementation class for the statelesshello bean */ public class statelesshelloimpl implements sessionbean /** 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) /** called by the ejb container when a client calls the create() method in /** called by the ejb container to wake this session bean up after it public void ejbactivate() /** called by the ejb container to tell this session bean that it is being public void ejbpassivate() /** called by the ejb container to tell this session bean that it has been public void ejbremove() /** returns a greeting for the named object */ public string greet(string thingtogreet) |
注意:
配置无状态session bean的过程和有状态bean几乎是一样的。只要确认已经配置bean为无状态的,可能需要在stateless的选项旁打上一个勾或者确认去除manages conversational state旁的选项。
列表6.8展示的是一个客户测试无状态session bean的代码
listing 6.8 source code for teststatelesshello.java import java.util.*; /** creates a jndi naming context for location objects */ /** asks the context to locate an object named "helloworld" and expects the statelesshellohome home = (statelesshellohome) system.out.println(session.greet("world")); /** destroy this session */ |
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关键字来传送自己:
| 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方法被调用后执行。
闽公网安备 35060202000074号