9

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

4

1 回答 1

18

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

每个 bean 实例调用一次。如果 bean 有一个单例范围(这也是方面的默认情况),它只会被调用一次。但是,您将无法访问httpServletRequestinsideinit()方法 - 还没有请求!

httpServletRequest 线程是否安全

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

这整个行为在4.5.4.5 Scoped beans as dependencies中有详细描述:

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

关于ThreadLocal

我不喜欢使用本地线程。

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

于 2012-05-10T20:56:17.530 回答