In the controller layer SpringMVC @Scope ("prototype") vs @Scope ("singleton")

I have the following controller code using SpringMVC:

@Controller @Scope("prototype") @RequestMapping("/messages") public class MessageController { @RequestMapping(value="/index", method=RequestMethod.GET) @ResponseStatus(HttpStatus.OK) @ResponseBody public String displayAllMessages(ModelMap model) { System.out.println(this.hashCode()); // processing return "messages"; } } 

When using @Scope("prototype") every request comes in, the output of this.hashCode() different, which means that a new instance of MessageController will be created with each request.

If you do not use @Scope("prototype") , by default there will be @Scope("singleton") , each request will be received, the output of this.hashCode() will be the same, that is, only one instance of MessageController will be created.

I'm not sure when to use @Scope("prototype") rather than?

+6
source share
2 answers

Let's say you pig-like code, and do something like this in your controller:

 private List<String> allMessages; public String displayAllMessages(ModelMap model) { allMessages = new ArrayList<>(); fillMessages(); model.put(messages, allMessages); return "messages"; } private void fillMessages() { allMessages.add("hello world"); } 

The controller will work with state: it has a state ( allMessages ), which cannot be shared between two requests. The controller is no longer thread safe. If it was called simultaneously to handle two simultaneous requests, there may be a race condition.

You can avoid this problem by making the controller a prototype: each request will be processed by a separate controller.

Or you could do the right thing and make the code standstill, and in this case, creating a new controller for each request would be useless, as the controller would be stateless and therefore thread safe. Then the scope can save the default value: singleton.

 public String displayAllMessages(ModelMap model) { List<String> messages = fillMessages(); model.put(messages, allMessages); return "messages"; } private List<String> fillMessages() { List<String> allMessages = new ArrayList<>(); allMessages.add("hello world"); return allMessages; } 
+9
source

If you are using singleton, you must make sure that you are not holding a state in your controller or that any state you are holding is intended to be shared between calls. Typically, business service components are constructed this way and are safe to enter into a singleton controller.

There are other scopes, depending on your spring configurations and libraries.

You can query beans and the session zone.

I would like to make the request of the controller class class cloudy, and not a prototype, since this will ensure that the same object is received by several using the controller from the same request.

You can use the session scope if you want to maintain the state that is stored in several requests in the session. But spring has other ways to achieve the same thing with @SessionAttributes

Finally, you can use java.inject.Provider injection in singleton bean with ProviderCreatingFactoryBean.

+1
source

Source: https://habr.com/ru/post/986905/


All Articles