Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In SpringMVC Controller layer, @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 use @Scope("prototype"), each request comes, the output of this.hashCode() are different, meaning that when each request comes, a new MessageController instance will be created.

If not use @Scope("prototype"), default will be @Scope("singleton"), each request comes, the output of this.hashCode() are same, meaning only one MessageController instance is created.

I'm not sure when should use @Scope("prototype"), when not?

like image 814
coderz Avatar asked May 10 '15 05:05

coderz


1 Answers

Let's say you 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");
}

Your controller would become stateful: it has a state (allMessages) that can't be shared between two requests. The controller is not thread-safe anymore. If it was called concurrently to handle two concurrent requests, there might be a race condition.

You could avoid this problem by making the controller a prototype: each request would be handled by a separate controller.

Or you could do the right thing and make the code stateless, in which case creating a new controller for each request would be useless, since the controller would be stateless and thus thread-safe. The scope could then keep its 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;
}
like image 58
JB Nizet Avatar answered Nov 05 '22 08:11

JB Nizet