Struts2中的拦截器线程是否为UNsafe?
我知道Struts2 Action类是线程安全的,因为操作放在Value Stack中。 值栈依次是Action Context的一部分。 由于Action Context是线程本地的,因此存储在Action Context(包括值栈)中的值对于每个线程都是唯一的。 因此,Actions是线程安全的。
但考虑一下拦截器:它们非常有用,它们为程序员完成所有繁琐的小工作……比如validation,获取参数值等等。但需要考虑的是:拦截器可以在多个请求之间共享。 那么这会使拦截器线程不安全吗?
考虑到这个问题,我试图在网上浏览一些与此问题相关的好文章。 我发现了一篇非常好的文章,他们已经清楚地提到了一个例子拦截器如何不是线程安全的。
该网页是: http : //www.bullraider.com/java/struts2/tutorials/interceptors-and-thread-safety
我从这篇文章中得知,拦截器线程不安全的主要原因是拦截器只创建了一次。 即每个拦截器只有一个对象。 因此,当线程之间共享Interceptor的相同实例时,实例字段不安全。
在文章的最后,提到有些情况,甚至拦截器都是线程安全的。 但他们没有提到任何此类案件。 我在网上冲浪找到答案……但徒劳无功:(
任何人都可以告诉我或给我一个链接,在那里我可以找到如何使拦截器线程安全(或拦截器线程安全时的情况是什么)?
任何不使用实例字段或其他共享状态的Interceptor都是线程安全的:
例如,查看解析HTTP请求参数和cookie,执行日志记录,访问检查,exception处理的所有内置拦截器 :它们不使用实例字段用于可变状态(*),而只是对它们获取的ActionInvocation
实例进行操作参数。
(*)有些配置参数的实例字段是在Struts启动时(在单个线程中)设置的,如ExceptionMappingInterceptor
,或者是线程安全的实例字段,如LoggingInterceptor
的Logger
。
如果您打算编写自己的Interceptor
,只需使用您传入的ActionInvocation
参数以及intercept()
方法中的局部变量。 避免让你的拦截方法synchronized
或将事物放入synchronized{}
块的诱惑 – 这将成为Struts对拦截器的单实例方法的瓶颈。
要回答评论中的问题:
(1)为每个线程创建一个动作实例如何不影响性能?或者它是什么?
使用现代JVM,创建对象的成本可以忽略不计。 如果通过避免昂贵的初始化来保持您的行动轻量化,例如不在操作中创建数据库连接但使用连接池,则应该对性能没有明显影响。
(2)你是否建议不要使用默认的拦截器堆栈,并始终使用自定义拦截器堆栈(其中所有使用实例变量的未使用的拦截器都被删除),以便它是线程安全的?
我不认为使用Struts 2发布和配置的任何默认拦截器都不是线程安全的; 即使他们使用实例字段(因为它们既可以用于配置,也可以用于像Logger
一样的线程安全)。
根据我的个人经验,如果你有充分的理由,你应该只触摸/更改拦截器堆栈(内置拦截器的线程安全性不是一个)。 如果你改变堆栈,许多事情会以意想不到的方式表现/破坏 – 运行其中一个内置堆栈,如“default”或“paramPrepareParam”,从长远来看可以节省很多挫败感。 添加自己的自定义拦截器通常比从现有堆栈中删除/重新排列拦截器更具破坏性。
可能相关的是,ScopeInterceptor.java类可能存在线程安全问题: Struts ScopeInterceptor类中的Java线程安全问题?