Andna
Andna

Reputation: 6689

Spring controllers - thread safety and storing resources

I have a question about spring mvc and thread safety.

We are developing web application that will be stored on tomcat. If I understand right, Tomcat creates thread per request and it has some thread pool. Now, dispatcher servlet is shared between requests and probably is thread safe.

But when I create controller like this:

@Controller
@RequestMapping("/manage")
public class QuestionManagementController {

he has Singleton scope so the same controller is used by every request that comes from every user.

I am wondering how this problem is usually solved:

1: are controllers created with Session scope? (but I think that there also could be problems if one user quickly do some things that may lead to race conditions in the controller).

2: controllers are scoped as request

3: creating stateless controllers that don't share any variables at class level, or have them in read only mode

or maybe there is some better "best practice" that solves this kind of problem.

I am asking this question, because now we have them as Singleton scoped, and there is a problem, that in most methods we are querying for user in the database , and we can't store this information in class level variable because of the scope. We could try to use some thread safe collection but later there could be other resources needing synchronized access.

Upvotes: 5

Views: 6788

Answers (1)

user180100
user180100

Reputation:

A lot of parameters can be added to the controller methods like request, session, principal etc to avoid your problem.

Usually there's a 3-layers architecture:

  • @Controller (they delegates to services)
  • @Service (they do the work using DAOs or Repositories)
  • @Repository (or DAOs, they do DB access)

So depending on what you are querying for in the DB, I would advise having a service, injected by Spring with a cache if hitting the DB is costly and everytime you need the stuff from the DB call the service (i.e. nothing stored in the controller class level)

A short example, let's say we are behind spring-security and everything need a fully logged-in user. We have an userData table where the key is the user login, we have an url /data to get a page showing my user data:

@Controller
@RequestMapping("/data")
public class UserDataController
{
    @Autowired
    private UserService userService;

    @RequestMapping(value = "", method = RequestMethod.GET)
    public ModelAndView data(final Principal principal) {
        Assert.notNull(principal); // throw if assertion fails
        Assert.hasText(principal.getName());

        final UserData userData = this.userService.findByUserName(principal.getName());
        Assert.notNull(userData, "userData not found");

        return new ModelAndView("userData", "userData", userData);
    }
}

@Service("userService")
public class userService 
{
    private static final String USERDATA_CACHE = "com.acme.foo.UserData";

    @Autowired
    private UserDataRepository userDataRepository;

    @Cacheable(USERDATA_CACHE)
    public UserData findByUserName(final String userName) {
        return this.userDataRepository.findByUserName(userName);
    }
}

@Repository
public class UserDataRepository
{
    // or use spring-data-jpa

    public UserData findByUserName(final String userName) {
        // query table userData and create an UserData from results.
    }
}

Here I use principal and spring ensure that this is current user one.

Refs:

Note sure if this answer fully to your concerns

Upvotes: 5

Related Questions