我正在使用Spring 3 AOP,我有一个需要访问HttpServletRequest的方面。它看起来像这样:
@Aspect
public class MyAspect {
@Autowired
private HttpServletRequest httpServletRequest;
public void init() {
// Do something once...
}
@Before("my pointcut here...")
private void myMethod() {
// I need the httpServletRequest...
}
@After("my pointcut here...")
private void myOtherMethod() {
// I need the httpServletRequest...
}
}
并且配置如下:
<bean id="myAspect" class="com.some.package.MyAspect" init-method="init" />
每个IoC容器只调用一次init方法,即使这是一个方面,httpServletRequest线程是否安全?如果不是,那么在执行建议期间获得它的最佳方法是什么?它是否是线程安全的?如果可能的话,我宁愿不使用本地线程。
答案 0 :(得分:17)
每个IoC容器只调用一次init方法
每个bean实例调用一次 。如果bean具有单例作用域(这也是方面的默认情况),则只会调用一次。但是,您无法访问httpServletRequest
内init()
方法 - 目前还没有请求!
是httpServletRequest线程安全
不是但不要担心。这实际上比它看起来要复杂得多。您正在向单个对象注入HTTP servlet请求(显然可以同时提供多个请求)。注入哪一个?没有(全部?)他们! Spring创建了一些复杂的代理(称为作用域代理),每次访问注入httpServletRequest
的方法时,它都会将它们委托给当前(到线程)请求。通过这种方式,您可以安全地在多个线程中运行方面 - 每个线程都将根据不同的物理请求运行。
4.5.4.5 Scoped beans as dependencies中详细介绍了这一整个行为:
[...]如果你想注入(例如)一个HTTP请求范围的bean到另一个bean ,你必须注入一个AOP代理来代替scoped bean。也就是说,您需要注入一个代理对象,该对象公开与范围对象相同的公共接口,但也可以从相关范围(例如,HTTP请求)检索真实的目标对象,并将方法调用委托给真实对象
关于ThreadLocal
:
我不想使用本地线程。
幸运的是 - Spring正在为你使用一个。如果您了解ThreadLocal
如何工作 - Spring会将当前请求放入本地线程,并在您访问httpServletRequest
代理时委托给线程本地实例。