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

9 aop spring servlets thread-safety 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...
    }
}
Run Code Online (Sandbox Code Playgroud)

并配置如下:

<bean id="myAspect" class="com.some.package.MyAspect" init-method="init" />
Run Code Online (Sandbox Code Playgroud)

init方法是否每个IoC容器只调用一次,即使这是一个方面,httpServletRequest线程是否安全?如果不是,那么在执行建议期间获得它的最佳方法是什么?它是否是线程安全的?如果可能的话我宁愿不使用本地线程.

Tom*_*icz 18

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

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

是httpServletRequest线程的安全

它不是,但不要担心.这实际上比它看起来要复杂得多.您正在向单个对象注入HTTP servlet请求(显然可以同时提供多个请求).注入哪一个?没有(全部?)他们!Spring创建了一些复杂的代理(称为范围代理),每次访问注入方法时,httpServletRequest它都会将它们委托给当前(到线程)请求.通过这种方式,您可以安全地在多个线程中运行方面 - 每个线程都将根据不同的物理请求运行.

4.5.4.5作为依赖关系的Scoped bean中详细描述了这整个行为:

[...]如果要将(例如)HTTP请求作用域bean注入另一个bean,则必须注入AOP代理来代替作用域bean.也就是说,您需要注入一个代理对象,该对象公开与范围对象相同的公共接口,但也可以从相关范围(例如,HTTP请求)检索真实的目标对象,并将方法调用委托给真实对象.

关于ThreadLocal:

我不想使用本地线程.

幸运的是 - Spring正在为你使用一个.如果您了解其ThreadLocal工作原理 - Spring将当前请求放入本地线程,并在访问httpServletRequest代理时委托给线程本地实例.