【问题标题】:Is ActionContext in Struts 2 unique to the current request?Struts 2 中的 ActionContext 对于当前请求是唯一的吗?
【发布时间】:2013-10-26 13:19:52
【问题描述】:

我正在使用一个自定义拦截器,它创建一个新的数据库连接,并在执行操作之前将此连接设置为当前操作。之后,拦截器关闭连接。

我正在寻找一种便捷的方式来与该操作使用的其他类/静态方法(例如模型)共享此数据库连接。例如,我可以调用像User.get( id )User.getEmail( id ) 这样的静态方法,而不必分别将数据库连接传递给每个方法。

我可以将 db 连接从拦截器设置到 ActionContext,方法是:

ServletActionContext.getActionContext().put("db", db );

然后我可以通过静态方法访问这个数据库连接,例如:

public class User implements Model
{ 
   public static String getEmail(int id)
   {
      Connection db = 
         (Connection) ServletActionContext.getActionContext().get("db");
      //...
   }
}

我的问题是,是否会为每个给定的请求生成一个新的ActionContext,所以我可以确定每次都会使用一个新的数据库连接?例如,如果我有 500 个人访问 mysite.com/fooAction,我能否确定这 500 个请求中的每一个都生成一个唯一的 ActionContext,并且每次调用 User.getEmail() 将只访问给定请求所特有的数据库连接?

谢谢。

【问题讨论】:

    标签: java servlets struts2 thread-local actioncontext


    【解决方案1】:

    回答问题:

    我的问题是,是否会为每个给定的 ActionContext 生成一个新的 ActionContext 请求,所以我可以确定每个人都会使用一个新的数据库连接 时间?

    是的。参考是java-doc。与Alfredo Osorio提供的类似,只是指的是2.3.x版本。

    你能说说用的是什么struts2版本吗?

    我找不到任何使用的版本

    ServletActionContext.getActionContext()
    

    但签名是

    ServletActionContext.getActionContext(javax.servlet.http.HttpServletRequest)
    

    回答comment关于线程局部是静态的并且仍然是每个请求的 ActionContext 实例是唯一的,因为这样做是因为

    ActionContext.getContext()
    

    在内部调用线程本地实例上的 get。

     actionContext.get()
    

    您可能会发现以下post 在这方面很有帮助。

    但要深入研究,方法

    ServletActionContext.getActionContext(javax.servlet.http.HttpServletRequest)
    

    采用与使用线程本地不同的路线。

    public static ActionContext getActionContext(HttpServletRequest req) {
        ValueStack vs = getValueStack(req);
        if (vs != null) {
            return new ActionContext(vs.getContext());
        } else {
            return null;
        }
    }
    
    public static ValueStack getValueStack(HttpServletRequest req) {
        return (ValueStack) req.getAttribute(STRUTS_VALUESTACK_KEY);
    }
    

    getActionContext

    getValueStack

    以下是一些额外的参考资料(源代码)。

    ValueStack

    OgnlValueStack

    ActionContext

    以下帖子也可能会有所帮助。

    1. will-a-new-actioncontext-and-valuestack-be-created-for-every-new-action-object

    2. struts2-actioncontext-and-valuestack

    更新 2:

    想要添加如上所述的here(上面的链接1),如果涉及ActionChaining,则使用其自己的拦截器堆栈和结果调用该操作。

    执行它的线程是相同的。

    值堆栈和参数被复制过来。请参阅 - ActionChainResult#execute(ActionInvocation)。

    一旦链式调用完成,动作上下文的状态就会被重置。 (参见 DefaultActionProxy#execute() )。

    部分信息:虽然在 DefaultActionInvocation#init(ActionProxy) 中设置了动作调用,但我无法确定它是否或在何处被重置。

    来源:

    DefaultActionInvocation

    DefaultActionProxy

    DefaultActionProxyFactory

    ActionChainResult

    FilterDispatcher(Deprecated)

    【讨论】:

    • 我使用的签名是ServletActionContext.getContext(),我不需要传入HttpServletRequest。我正在使用最新版本( 2.3.15.2 )。有什么想法吗?
    • 如果您能在stackoverflow.com/questions/19755939/… 上提供任何帮助,那就太好了
    • @ClickUpvote 方法ServletActionContext.getContext()实际上来自ActionContext。见ActionContext.getContext()。如上所述,这会调用actionContext.get(),其中actionContext 是一个ThreadLocal 变量。此方法与问题中的方法签名不同。也许您可以相应地更新您的问题。
    • 在任何一种情况下,答案是否相同,即每当我执行ServletActionContext.getContext() 时,每个请求都是唯一的?
    • 简短的回答是肯定的。将不得不回过头来了解具体情况。
    【解决方案2】:

    我的问题是,是否会为每个给定的 ActionContext 生成一个新的 ActionContext 请求,所以我可以确定每个人都会使用一个新的数据库连接 时间?

    由于 ActionContext 使用 ThreadLocal,它是线程安全的。 Struts 2 为每个请求创建一个ActionContext,每个请求都有自己的线程。所以是的,如果您创建一个新连接并将其存储在 ActionContext 中,每个线程都会有自己的连接。但我不建议您将连接存储在 ActionContext 中,因为这会将您与 Struts 2 结合起来,这不是一件好事,而且您的服务也不应该调用特定于 Web 的类,因为它也会结合它们。

    From Struts 2 Javadoc:

    ActionContext 是执行动作的上下文。每个 上下文基本上是一个动作需要的对象容器 执行,如会话、参数、语言环境等。

    ActionContext 是线程本地的,这意味着存储在 ActionContext 每个线程都是唯一的。见 ActionContext.ActionContextThreadLocal 类以获取更多信息。这 这样做的好处是您无需担心特定于用户的问题 动作上下文,你就明白了:

    ActionContext 上下文 = ActionContext.getContext();最后,因为 您不必担心使您的线程本地使用 动作线程安全。

    ActionContext摘录:

    public class ActionContext implements Serializable {
    
        static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();
        ....
    }
    

    【讨论】:

    • 问题.. 如果在我的课程开始时,我有以下行:private static Connection db =(Connection)ServletActionContext.getActionContext().get("db");,这是否也会作为线程本地执行,或者在每个方法中获取数据库会更好个人?
    • @ClickUpvote 不会是线程本地的。它还会给你一个 NullPointerException,因为只要类加载器加载类,就会调用 static,那时 Struts 2 甚至还没有初始化,也没有请求。所以你应该在方法内部调用它。
    • 谢谢伙计.. 非常感谢您的帮助。这是可能让您困扰很长时间的问题之一,或者您认为没有解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 1970-01-01
    相关资源
    最近更新 更多