Reputation: 467
As far as I know, Spring beans are singleton by default.
What I want is make beans thread-safe considering instance attributes.
I'll try to show you using a simple example.
Consider the following code:
@Controller
public class MyServlet {
@Autowired
private HelloService service;
@RequestMapping(value="/hello", method = RequestMethod.GET)
public void sayHello(HttpServletRequest req, HttpServletResponse res) throws IOException {
service.doStuff();
}
}
public class HelloService {
private int i = 1;
public void doStuff() {
System.out.println("Started " + i);
i++;
System.out.println(Thread.currentThread().getName() + " Done " + i);
}
}
The output will be something like this:
32911580@qtp-28064776-0 - Started 1
7802158@qtp-28064776-2 - Started 2
32911580@qtp-28064776-0 - Done 3
7802158@qtp-28064776-2 - Done 3
This prove the "i" var is shared between multiple threads.
I've also tryed to define the HelloService bean as prototype, like this
<bean id="helloService" class="my.package.HelloService" scope="prototype" />
but the result is the same.
The only ways I found to solve this are: - move the declaration into doStuff() method, but it's not what I want - make the doStuff() method, but this means have locks
What I would like is have a new instance of HelloService on every call.
Can anyone help me? Thanks in advance.
I found the solution with method injection using lookup-method. http://static.springsource.org/spring/docs/3.1.1.RELEASE/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection
Upvotes: 3
Views: 19430
Reputation: 46
I've also tried to define the HelloService bean as prototype, but the result is the same.
You got the same result because your MyServlet
is singleton. So you have only one MyServlet
instance, hence you have only one HelloService
instance. If you make MyServlet
as prototype bean as well, you will be get every time new instances for both
Upvotes: 1
Reputation: 1167
Adding to Thomas' answer, for a service bean, request-scope is the best choice for a stateful & thread-safe component, since only one instance is normally called for in that scope.
If multiple (stateful & thread-safe) beans are needed within a particular application scope, prototype-scope would be the most appropriate choice.
Upvotes: 1
Reputation: 1633
Since you have only one instance of MyServlet you will also have only one instance of HelloService.
One of the following spring scopes help: request A new instance for each HTTP request. session A new instance of the class for each new HttpSession created in a servlet container.
This will change the semantics of your code. If you declare the bean in the scope request your counter will always be 1.
To have one unique counter without locks you could use java.util.concurrent.atomic.AtomicInteger.
On the other side there is nothing bad about locks. The performance impact is neglectible in most except extreme cases.
After you have built your application check it with http://vmlens.com for race conditions.
Upvotes: 3