使用struts2操作处理许多同时发生的AJAX请求

时间:2009-06-25 19:06:31

标签: java multithreading tomcat struts2

我有一个struts2动作,通过获取一些请求参数,调用返回XML数据的远程服务,然后通过XSL转换数据并通过Stream Result返回结果XHTML来响应AJAX请求。响应因给定参数而异。

这是带有一堆东西的动作类:

public class ServiceHandler extends ActionSupport {
    private ByteArrayInputStream inputStream;

    public String execute(){

        String response = "";

        // Get request parameters
        // Make a request to a remote server via an http connection
        // Transform result via XSL

        //uses dom4j for XML/XSL stuff
        //this should never be empty
        response = resultDoc.asXML();

        inputStream = new ByteArrayInputStream(response.getBytes()); 
        return "success";
    }

    public ByteArrayInputStream getInputStream(){
        return inputStream;
    }
}

以下是重要的struts.xml位:

<action name="sh" class="ServiceHandler">
    <result name="success" type="stream">
        <param name="contentType">text/html</param>
        <param name="contentDisposition">inline;filename="response.html"</param>
        <param name="bufferSize">1024</param>
        <param name="allowCaching">false</param>
    </result>
</action>

我的问题是,当我有多个请求同时进行时,所有调用ServiceHandler操作,有时响应是完全空白的(应该永远不会发生),有时响应在开始或结束时被一些随机切断数量,有时响应被切换,以便AJAX请求者收到错误的响应。

我知道这是一个线程安全问题,我已将所有重要的变量定义移到execute()方法中,这样它们就不是实例变量(因此被所有人共享)。作为实例变量的唯一有趣的变量是inputStream,我正在将其视为我的问题的原因。

有没有办法让inputStream变量是线程安全的?或者是否有另一种我没有看到的解决方案?

3 个答案:

答案 0 :(得分:0)

我只熟悉Struts 1,但请看看DonwloadAction。或者只使用普通的struts Action,将结果直接写入响应对象并返回null作为转发。

答案 1 :(得分:0)

我根本没有进入Struts 2,但是如果你真的必须返回“成功”结果并且无法直接写入输出,那么这似乎是一个使用ThreadLocal的好地方保持您的流本地到当前线程。 (有关模式的更多信息,另请参阅线程本地存储上的Wikipedia article。)

答案 2 :(得分:0)

感谢Henning带领我朝着正确的方向前进。我没想过直接写入响应输出流,因为在struts2文档中没有提到它。

将响应直接写入输出流的好处是您不需要为inputStream创建实例对象。这会将所有数据保存在execute()方法中,这对其他线程是安全的。

这是一个修改后的动作类,它直接写入输出流并返回null结果。

import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;

public class ServiceHandler extends ActionSupport {
    public String execute(){

        String response = "";

        // Get request parameters
        // Make a request to a remote server via an http connection
        // Transform result via XSL

        //uses dom4j for XML/XSL stuff
        //this should never be empty
        response = resultDoc.asXML();

        HttpServletResponse httpResponse = ServletActionContext.getResponse();
        try{
            httpResponse.getOutputStream().print(response);
        }
        catch(IOException e){
            return "failure";
        }

        return null;
    }
}

这似乎解决了我遇到的问题。