How to have thread safe controller in spring boot

2019-03-31 17:17发布

问题:

How should I create a controller which is thread safe?

As per the best practice controllers are singleton.

Consider the below code in which im storing user data through a autowired service Object ,which makes my code stateful. How would i make the below code thread safe.

@RestController
class ApiController {

    @Autowired
    IDbService< User > iDBService;

    @RequestMapping(value = "/api/adduser", method = RequestMethod.POST)
    public ResponseEntity<User> createUser(@RequestBody User user){

        User savedUser=iDBService.create(user);

        return new ResponseEntity<User>(savedUser, HttpStatus.CREATED);
    }

Here is my Service implementation. I have shared variable in my service

public class IDbServiceImpl<T> implements IDBService<T>{

@Autowired
GenericRepository<T, Serializable> genericRepository;

@Override
public T create(T object) {
    return  genericRepository.save(object);
}

}

回答1:

Your controller is a singleton by default and your service is singleton by default too.

Therefore in order to make them thread safe you have to make sure that the operations that take place inside the service must be thread safe, in case of changing the state of an object inside the service ie. a list.

In case of using a rdbms then you have a transaction related problem.

If you use spring and Jpa, the transaction manager will take care for your updates provided that you use @Transactional. In case of plain jdbc method then you can either use pure jdbc and do the transaction handling on your own or use spring-jdbc that comes with a transaction manager.

If you want the database rows not to be changed in case of a write in progress then you have to take into consideration row-locking related mechanisms. – gkatzioura Feb 7 at 15:23

In case of JPA using @Transactional will do the work. However depending on your application you might have to consider locking. Check this article on locking with jpa.



回答2:

Controllers are singletons, therefore they should be implemented in a thread safe manner.

Design your application in a way that controllers are stateless. Add transactional support in your @Repository layer.

Example:

public class GenericRepository<T, Serializable> {
 @Transactional
 public void save(T object) {
  // save user
 }
}

You could use Spring declarative transaction management mechanism. The @Transactional annotation itself defines the scope of a single database transaction.



回答3:

Your controller looks thread safe. As there is no instance variable storing the state. User object will be different for each request and will be resolved by the MVC framework.