Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Autowired - Instantiate new bean

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.

like image 302
isyndicate Avatar asked Sep 24 '13 04:09

isyndicate


3 Answers

By default when you use @Autowired spring bean scope is singleton. That means spring injects the same singleton object where ever you use @Autowired. By making scope prototype you are instructing Spring to create new objects for each @Autowired injection, and so in your interceptor will have its own copy of HttpClient and cant see other HttpClient objects.

So better approach is use the singleton scope, Use request attributes or threadlocal to carry around your custom properties down the request thread. ie instead of modifying HttpClient properties in interceptor, just set some request attributes or threadlocals and handle these custom settings within CustomHttpClient class methods.

like image 154
Subin Sebastian Avatar answered Nov 03 '22 00:11

Subin Sebastian


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.

like image 25
Vineet Kasat Avatar answered Nov 03 '22 00:11

Vineet Kasat


All beans declared in the Spring container enther by XML or by annotation support are by default singletons. If you inject a bean with scope set to prototype into a singleton e.g. a controller it will inject it only once. There is a way to achieve this goal. This is how you should declare a bean scoped as a prototype. This means that the container will always give you a new instance each time this bean is called upon from the container.

<bean id="shoppingCart" class="example.ShoppingCart" scope="request">
     <aop:scoped-proxy />
</bean>
like image 29
Khush Avatar answered Nov 02 '22 23:11

Khush