My FAQ,最新最全的IT技术FAQ
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 未整理篇 | 技术讨论
  当前位置:> Bea专区 > WebLogic Portal
在页面流中调用控件时关于控件生命周期的考虑
作者:Lawrence Jones 时间:2005-10-19 16:10 出处:互连网 责编:小渔
              摘要:最近的WebLogic Workshop技术支持案例介绍了在页面流中调用JMS控件的情况。如果从Web 服务(JWS)中调用,控件的调用功能工作正常;但是,如果从页面流(JPF)中调用,控件将会抛出一个weblogic.jms.common.IllegalStateException异常。其中的差别在于控件的生命周期,本文将详细分析这个问题。
最近的WebLogic Workshop技术支持案例介绍了在页面流中调用JMS控件的情况。如果从Web 服务(JWS)中调用,控件的调用功能工作正常;但是,如果从页面流(JPF)中调用,控件将会抛出一个weblogic.jms.common.IllegalStateException异常。其中的差别在于控件的生命周期,本文将详细分析这个问题。

以下页面流(JPF)中的createTextMessage()调用将会抛出weblogic.jms.common.IllegalStateException异常:

package f1.Test;
import com.bea.wlw.netui.pageflow.Forward;
import com.bea.wlw.netui.pageflow.PageFlowController;
import javax.jms.JMSException;
import javax.jms.TextMessage;
 
public class TestController extends PageFlowController
{
    /**
     * @common:control
     */
    private f1.MyJMS myJMS;
 
    /**
     * This method represents the point of entry into the pageflow
     * @jpf:action
     * @jpf:forward name="success" path="index.jsp"
     */
    protected Forward begin() throws JMSException
    {
        TextMessage msg = myJMS.getSession().
                            createTextMessage("hello");
        myJMS.sendJMSMessage(msg);
        
        return new Forward( "success" );
    }
}
 



这段代码看起来非常简单——得到一个JMS会话对象、创建一个消息、然后发送。MyJMS是一个普通的JMS控件,它的目的是发送JMS消息类型(而不是Text/XMLBean、对象或字节消息这些其他的消息类型)的消息到JMS队列中。


如果把同样的代码放到Web 服务操作中,一切工作正常。到底什么地方有问题呢?

问题的秘密位于底层。控件是由控件容器来调用的,容器负责创建和销毁控件,保证生命周期APIonAcquire()onRelease()、等等)在适当的时候被调用,并提供com.bea.control.ControlContext对象。借助该对象,控件可以从控件实例声明中获取Javadoc标签信息,然后根据这些标签的内容执行相应的操作。如果没有容器,控件将无法知道自己所处的调用上下文。


当然,在执行操作之前,控件容器需要首先被初始化。当前的控件容器实现依赖于J2EE EJB容器的安全和事务上下文,所以它需要运行在EJB上下文之中。当在JWS JPD中调用控件时,控件并不是位于“顶级”。因为此时它已经位于一个EJB中——如果从非会话方法中调用,它位于一个无状态会话bean中;如果从会话方法中调用,它将位于一个实体bean中。控件容器代码是在该EJB的上下文中被执行的。

页面流实际上是一个servlet。它是一个web层、而不是EJB层成员。因此,当在页面流中调用一个控件方法时,需要使用一个位于顶级的EJB来包含控件容器。

构建阶段生成的、用于处理该问题的EJB是一个名为GenericStatelessSLSB的无状态会话bean。它是一个普通的无状态会话bean——应用了J2EE容器池技术,因此该bean不必每次调用都从头开始构建。但每次调用使用的bean可能不是一个。

控件容器代码决定什么时候应该获得及释放资源。在JWS中,当方法(针对非会话方法)或会话(针对会话方法)结束时,Web 服务容器会通知控件容器,此时资源就可以被释放掉。如果从web层进行调用,我们无法判断下次调用在什么时候发生(因为采用的是无状态会话bean,所以无法确定下次接收调用的是否是同一个bean)。因此,容器只能在每次控件方法被调用之前调用onAcquire()方法,在每次控件方法被调用之后调用onRelease() 方法。


对于前面的场景,不幸的地方恰恰在于每个方法调用之后都调用了onRelease()getSession() 调用就是一个这样的方法:容器在调用getSession() 之前调用onAcquire();在调用getSession()之后调用onRelease(),即使接着就要调用createTextMessage()。结果,从getSession() 得到的JMS会话在被createTextMessage() 使用之前,就在onRelease()中被释放掉了。


如何才能修复这个问题呢?很显然,修改API使事件的发生更合理是最好的方法。目前,我们也可以采用一些方法绕过这个问题。

我们需要在web层调用中重新调用上面提到的被创建成顶级控件的会话bean。一旦有了一个EJB,就没必要(也会降低性能)在每层都创建额外的EJB。因此,我们可以编写一个自定义控件来包装想要执行的多个方法,使这些方法在新控件的同一个方法中执行。

package f1; 
 
import com.bea.control.*;
import javax.jms.JMSException;
 
/**
 * @jcs:jc-jar label="MyWrapper"
 * @editor-info:code-gen control-interface="true"
 */
public class MyWrapperImpl implements MyWrapper, ControlSource
{ 
    /**
     * @common:control
     */
    private f1.MyJMS myJMS;
 
    static final long serialVersionUID = 1L;
 
    /**
     * @common:operation
     */
    public void customSendMessage() throws JMSException
    {
        TextMessage msg = myJMS.getSession().
                            createTextMessage("hello");
        myJMS.sendJMSMessage(msg);
    }
}
 



现在,控件容器将会调用onAcquire(),然后调用用户自定义控件的customSendMessage() 方法。该方法依次调用getSession()createTextMessage()sendJMSMessage()方法。这中间不会发生对onRelease()的调用,因为控件的方法调用还没有完成。最后,当customSendMessage()调用结束时,onRelease()才被调用,JMS会话被释放。

总之,控件被设计成一种内在的EJB层部件。如果可能的话,请避免在web层调用它们(可以调用web 服务作为替代)。如果无法避免,请记住每次顶级方法调用都是针对不同的无状态会话bean,因此不能指望连续的调用可以保留状态。如果在一个或多个控件上有多个方法需要连续调用,请将这些调用包装成自定义控件上的一个方法并调用这个新方法。

 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 myfaq.com.cn All rights reserved. www.myfaq.com.cn 版权所有