【问题标题】:Struts 2 resetting action instance while its still in interceptorStruts 2 在拦截器中重置动作实例
【发布时间】:2013-11-03 17:46:22
【问题描述】:

似乎如果我对同一个操作(例如 mysite.com/fooAction)发出两个并发请求,那么 struts 会重置第一个操作的实例,而该实例可能仍在拦截器中。

例如,如果我的拦截器中有以下代码:

action =  ai.getAction();
String result = ai.invoke();
logger.debug("Orig action : " + action.toString()  +" , now : " + ai.getAction().toString() );

如果我对同一个操作发出两个并发请求(例如使用 javascript),那么行:

logger.debug("Orig action : " + action.toString()  +" , now : " + ai.getAction().toString() );

产生两个不同的toString() 代码,表明原始操作与上一个操作在不同的实例中。

这是一个大问题,因为现在,如果我在拦截器中有任何代码,它会在我的操作上设置某些东西,例如执行以下操作:

MyAction action =  (MyAction) ai.getAction();
Auth auth = new Auth ( action.getSession() );
action.setAuth(auth);
action.setCookiesMap( Util.getAllCookies() );
String result = ai.invoke();

那么不能保证我在操作中设置的所有这些东西实际上都会传递给正确的实例。即,当调用ai.invoke() 时,它实际上可能调用了一个完全不同的动作实例,该实例具有不同的cookie 或其他数据集。这可能会导致不同的用户被授予访问彼此数据的权限。

我在所有这些方面都是正确的吗?如果是这样,是否有解决此问题的方法?因为这似乎完全违背了拦截器的目的。

【问题讨论】:

    标签: java struts2


    【解决方案1】:

    如果我正确理解了问题 - 如果发出单个请求,则打印操作引用的结果表明它们是相同的。

    但是,如果发出并发请求,则操作引用会有所不同。

    如果确实如此,那么它可能是由于自定义。

    默认情况下,在 DefaultActionInvocation is in createAction 的情况下,“action”引用被初始化的唯一地方,而 DefaultActionInvocation is in createAction 又只在同一类的 init(ActionProxy) 中调用,而后者又应该只被调用一次,并且从prepare() of DefaultActionProxy 完成,而后者又只能从createActionProxy() of DefaultActionProxyFactory 调用。

    因此,对于给定的 ActionInvocation 实例,操作将(应该)始终相同。

    更新 2 (Regarding the example s2 project):

    虽然我没有实际运行代码,但我确实通过了它。

    Json 拦截器是有状态的。但是,它必须是无国籍的。这解释了为什么并发请求会导致操作实例不同。

    根据拦截器文档here:

    拦截器是跟随拦截器的无状态类 模式,见于 javax.servlet.Filter 和 AOP 语言。
    ...

    拦截器必须是无状态的,并且不能假设新实例会 为每个请求或操作创建。

    据我了解:

    第一个请求在拦截器中分配本地Action实例并进入休眠状态。

    第二个请求重新分配 Action 实例(拦截器是单例的)并且也进入睡眠状态。

    第一个请求唤醒并继续执行。在返回并再次比较动作实例时,在第二个请求的拦截器中看到动作实例,并再次从 ActionInvocation 获取当前请求的动作实例。他们确实会有所不同。这解释了观察到的行为。此外,即使没有调用 ai.invoke() 或 ai.invokeActionOnly(),它也应该是可见的。

    此外,“servletConfig”拦截器和其他一些拦截器已经包含在“defaultStack”中。你可以找到详情here

    【讨论】:

    • 请查看我的编辑,其中我提供了一个示例项目来测试此行为,它表明通过ai.getAction() 获得的动作参考与ai.invokeActionOnly() 之后获得的参考不同,如果同时多次请求同一个动作类。
    • @ClickUpvote 我已经更新了答案。简单来说,拦截器应该是无状态的。
    • 你是对的。需要明确的是,我将第一个 action 存储为类字段,而不是 intercept() 方法的局部变量。因此,在并发请求期间每次调用 intercept() 方法时都会重置它。使 action 成为局部变量解决了这个问题。以后编写拦截器的任何人都应该记住,拦截器是单例的。所以他们可以避免我犯的同样的错误。
    • @ClickUpvote 这在大红色警告框中的文档中突出显示。此外,当提出这样的问题时,代码的上下文很重要很多——无法从问题中看出拦截器是有状态的。
    • @ClickUpvote 考虑查看更新版本的文档;大红框中关于线程安全的说明是 2007 年添加的。
    猜你喜欢
    • 2013-06-18
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多