Spring MVC: how to build a thread-safe Controller

By , last updated July 6, 2019

Controllers in Spring MVC are designed to be shared between requests. Each controller has a default singleton scope so if you are using controllers you need to be aware of that. The easiest way to make sure your controller is thread-safe is to avoid class variables. F.ex. this example from Spring MVC tutorial:

@Controller
@RequestMapping("/editPet.do")
public class EditPetForm {

    private final Clinic clinic;

    public EditPetForm(Clinic clinic) {
        this.clinic = clinic;
    }

    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String processSubmit(
            @ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {

        new PetValidator().validate(pet, result);
        if (result.hasErrors()) {
            return "petForm";
        }
        else {
            this.clinic.storePet(pet);
            status.setComplete();
            return "redirect:owner.do?ownerId=" + pet.getOwner().getId();
        }
    }
}

In this example we can have a serious issue regarding thread-safety: private variable clinic. If there is a situation where two different requests access the controller simultaneously, one of them will instantiate the controller and begin to process the form, then the other one comes in. The result from processing of the first request will be sent to the other one, thus the requests receive wrong data or nothing.

The solution to the problem may be the following:
1. Annotate Controller with @Scope(“request”) or @Scope(“session”)
2. Move private variable into one of the methods or save it in session or model.

Resources: