3
votes

Well, I have 3 layers from Controller->Service->Repository made in MVC Spring 3 design. Now, my question is, since the default scope is defined as Singleton, are they thread-safe?

Here is the code look like:

UserController.java

@Controller
@RequestMapping("/users")
public class UserController extends ExceptionExtension {
     @Autowired
     private IUserService userService;

     @RequestMapping(value = { "/update", "/update/" }, method = RequestMethod.GET)
     public String updateUser(@RequestParam("email") String eMail, ModelMap model)
        throws Exception {

          if (eMail.isEmpty() || eMail == null) {
              throw new ArgumentIsEmptyException("Required String parameter 'email' is empty");
          } else {
              UserModel userModel = userService.setUser(eMail);

              if (userModel != null) {
                  model.put("roleList", userService.setRoleList());
                  model.put("title", "Update Existing User");
                  model.put("post", "/users/post/update");
                  model.put("userForm", userModel);

                  return "users.update";
              } else {
                  model.put("title", "Update Existing User");
                  model.put("result", "<font color='red'><u>" + eMail + "</u> does not exist in the database.</font>");
                  model.put("flag", "Error");

                  return "users.result";
              }
          }
     }
}

UserService.java

public class UserService implements IUserService {

    @Autowired
    private IUserManager userManager;

    public UserModel setUser(String eMail) {
        UserModel userModel = new UserModel();
        Entity userEntity = userManager.getUser(eMail);

        if (userEntity != null) {
            userModel.setEMail(eMail);
            userModel.setRole(userEntity.getProperty("role").toString());
            userModel.setEnable((Boolean)userEntity.getProperty("enable"));

            return userModel;
        } else {
            return null;
        }
    }
}

Say, User A and User B are concurrently running the same url but different parameter.
User A request => "http://domain.com/users/[email protected]".
User B request => "http://domain.com/users/[email protected]".

Since the Controller is singleton, will the User A eMail variable overlaps to the User B one and the vice versa?

I am finding hard to understand on how is the Singleton Thread-Safe working in this scenario. Should my @Service and @Repository declare as @Scope("prototype) so the inner method variables are isolated from new instantiate?

====>

with Scope("request") to my @Service layer, I hitted this error message :/

3328 [main] ERROR org.springframework.web.context.ContextLoader - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'roleController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.company.dashboard.service.IRoleService com.company.dashboard.controller.RoleController.roleService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'roleService': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

2

2 Answers

1
votes

Here Thread Safety depends upon the internal locking of userService in case of scope singleton

This is what ultimately happens => The same userSpace bean is used for both the requests and both requests concurrently access userService bean. So the IUserService needs to be thread safe for the whole operation to perform well.

Or

put the scope to request.

In which case a new bean is allocated for every request and the whole operation is thread-safe, thanks to thread confinement. Provided you code accordingly in IUserSpace

0
votes

if you make any layer scope: prototype, like suggested in the comments, you are merely moving the problem again to the layer underneath.

You need to decide where you want your transaction demarcation. Typically, this is done at the level of calls to a service. Spring can handle that for you.

Controllers, Services and Repositories should usually be implemented in a stateless fashion, that is to say that those classes don't have any instance variables that your methods modify. Else you will become vulnerable to race-conditions. Finally, your datastore must support the use of transactions.

You use the Google Appengine datastore. It has a very specific approach to transactions, unlike any RDBMS. To talk to to appengine from a Java app I recommend 'Objectify'. Start out by reading [about its concepts] (and the the concepts of the underlying BigTable datastore1.