用于自动装配的HTTPServletRequest bean的Spring AOP和方面线程安全性

时间:2012-05-10 20:50:52

标签: spring servlets thread-safety aop spring-aop

我正在使用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线程是否安全?如果不是,那么在执行建议期间获得它的最佳方法是什么?它是否是线程安全的?如果可能的话,我宁愿不使用本地线程。

1 个答案:

答案 0 :(得分:17)

  

每个IoC容器只调用一次init方法

每个bean实例调用一次 。如果bean具有单例作用域(这也是方面的默认情况),则只会调用一次。但是,您无法访问httpServletRequestinit()方法 - 目前还没有请求!

  

是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代理时委托给线程本地实例。