6

Need some help with Spring autowiring, and scopes.

Here is the basic app structure:

  1. I have an CustomHttpClient, annotated as @Component, and also pulling some config-related properties from application.properties file (via @Value annotation).

  2. CustomHttpClient is used by several services in my application. Whenever I'm using the CustomHttpClient, I autowire an instance of that via:

    @Autowired
    private CustomHttpClient httpClient;
    
  3. I use interceptor to modify some of the variables inside CustomHttpClient, like so:

    public class MyInterceptor extends HandlerInterceptorAdapter {
    @Autowired CustomHttpClient httpClient;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    httpClient.setSomeProperty(newValue);
    ...
    

Now, here is the problem. If I have everything set up as described above, then whenever I change any setting of the CustomHttpClient via interceptor, that new value is persisted for all other clients, as long as VM is running. So when I run httpClient.setSomeProperty() - that setting is now permanently saved. Even if I connect to the application from another client.

Basically what I need to have are two things:

  1. Still being able to override default settings of the CustomHttpClient via interceptor (request interceptor, configured via ).
  2. Make sure a new instance of CustomHttpClient is created for every request (after the interceptor does its' magic).

I tried changing the scope of CustomHttpClient to @Scope("prototype"), but that way I can no longer change settings of CustomHttpClient with an interceptor.

4

3 回答 3

8

默认情况下,当您使用@Autowiredspring bean 时,作用域是单例的。这意味着 spring 会在您使用的任何地方注入相同的单例对象@Autowired。通过设置作用域prototype,您指示 Spring 为每个 @Autowired 注入创建新对象,因此在您的拦截器中将拥有自己的 HttpClient 副本并且看不到其他 HttpClient 对象。

所以更好的方法是使用单例范围,使用请求属性或线程本地在请求线程中携带您的自定义属性。即,无需在拦截器中修改 HttpClient 属性,只需设置一些请求属性或 threadlocals 并在CustomHttpClient类方法中处理这些自定义设置。

于 2013-09-24T06:06:52.953 回答
1

If your interceptor is only addding some properties then using thread local should be a better option. You can call ThreadLocal.set(custom Map) and use it wherever you want for the running thread and when your program is going to leave your controller you can call ThreadLocal.Unset which will clear the value stored.

This way you wont need a new instance of HttpcLient everytime, also a new instance every time would be a serious flaw. And you will be able to use your custom map anywhere you want in the running thread.

于 2013-09-24T04:53:10.620 回答
1

通过 XML 或注释支持在 Spring 容器中声明的所有 bean 默认情况下都是单例。如果您将一个范围设置为原型的 bean 注入到一个单例中,例如一个控制器,它将只注入一次。有一种方法可以实现这一目标。这就是你应该如何声明一个作用域为原型的 bean。这意味着每次从容器调用此 bean 时,容器总是会为您提供一个新实例。

<bean id="shoppingCart" class="example.ShoppingCart" scope="request">
     <aop:scoped-proxy />
</bean>
于 2013-09-24T07:14:30.107 回答