Scope of Controllers ,Service,Repository in Spring Web Application?
Solution 1
The services and DAOs should be stateless. This would allow you to configure them as Spring singletons. I hope this is what you mean when you say "singleton".
All threading concerns, including the thread pooling, will be taken care of by the infrastructure: your web/Java EE server and Spring DI.
Solution 2
Annotate your service class with @Service and Dao class with @Repository .
<context:component-scan base-package="x.y.z.service, x.y.z.dao" />
it will automatically creates singleton bean for your class
Solution 3
Unless your DAOs need instance fields, there's no need for them to be request scoped. As long as your Hibernate Session
is retrieved with Session#getCurrentSession()
, which is thread bound, a single DAO instance to handle all requests is fine. The same applies for Service classes and Controllers.
As for your statement
which I think slow down the response to the user
That is not always true, depending on how heavy the object is. The Servlet container and your Spring DispatcherServlet
are instantiating so many objects anyway. You shouldn't see a big change.
Creating a pool of these objects would be overkill. Note: Those wouldn't be Thread pools, just object pools.
beinghuman
Updated on July 26, 2022Comments
-
beinghuman almost 2 years
I am creating a web application using spring ,hibernate. Suppose multiple users wants to register.I will create a registration bean(prototype or request or session scoped) and autowire it in Controller.
Now I am passing this bean to Registration Service(annotated with "@transactional" annotation) which is also autowired in the controler. This service will pass recieved registeration bean object to DAO(This DAO is autowired in the service)If service and DAO are singelton would'nt the requests be mixed up for multiple users?
Here is what I have done :I have created the scope of service and DAO as "request". Is this the right approach? or what else could I do to make the service and DAO singelton?
My logic behind request scoped: The reason for making service and DAO as request scoped is if multiple users call registerationService.registerUser(bean); from the controller at same time and scope is singelton then there would be no consistency coz there one object's methods are called with different inputs.
LET ME KNOW WHERE I AM WRONG.
Registeration Bean
@Component(value="registerBean") @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "request") public class RegisterBean { @NotNull private String userName; private String lastName; @NotNull private String firstName; String email_address; String password; String confirmPassword; String gender; //getters and setters }
Controller
package com.ClickToShop.controllers; @Controller @SessionAttributes("user_info") public class LoginPageController { RegisterBean registerBean;//used RegisterationService registerationService;//used @Autowired @Qualifier("registerationService") public void setRegisterationService(RegisterationService registerationService) { this.registerationService = registerationService; } @Autowired @Qualifier("registerBean") public void setRegisterBean(RegisterBean registerBean) { this.registerBean = registerBean; } @ModelAttribute(value = "registerBean") RegisterBean returnModelAttribute() { return registerBean; } @RequestMapping(value = "/login-page.html") public String showLoginPage() { System.out.println("Showing login page"); System.out.println(registerBean); return "login-page"; } @RequestMapping(value = "/newuser-register", method = RequestMethod.POST) public String registernewuser( @ModelAttribute("registerBean") @Valid RegisterBean bean, BindingResult result,final RedirectAttributes redirectAttr) throws NoSuchAlgorithmException, UnsupportedEncodingException { //some validation code registerationService.registerUser(bean); return "redirect:successRegisteration"; } } } Service Layer @Service("registerationService") @Transactional @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS,value="request") public class UserServiceImpl implements RegisterationService { private User_Details_Pojo userToRegisterPojo; private AbstractHibernateDAO UserDAO; @Autowired public void setUserDAO(AbstractHibernateDAO userDAO) { UserDAO = userDAO; } @Autowired @Qualifier("userToRegisterPojo") public void setUserToRegisterPojo(User_Details_Pojo userToRegisterPojo) { this.userToRegisterPojo = userToRegisterPojo; } //main implementation code starts here @Override public void registerUser(Object userBean) { RegisterBean bean=(RegisterBean) userBean; //bean or model is converted to pojo UserDAO.save(userToRegisterPojo);//calling DAO with specified pojo } }
DAO:
public abstract class AbstractHibernateDAO<T extends Serializable> { public Class<T> clazz;//class object reference protected SessionFactory mysessionFactory; @Autowired public void setMysessionFactory(SessionFactory mysessionFactory) { this.mysessionFactory = mysessionFactory; } public T findOneByName(final String name){ return (T) getCurrentSession().createQuery("from "+clazz.getName()).uniqueResult(); } public void setClazz(final Class<T> clazzToSet) { this.clazz = clazzToSet; } public T findOne(final Long id) { return (T) getCurrentSession().get(clazz, id); } @SuppressWarnings("unchecked") public List<T> findAll() { return getCurrentSession().createQuery("from " + clazz.getName()).list(); } public void save(final T entity) { getCurrentSession().merge(entity); } public void update(final T entity) { getCurrentSession().update(entity); } public void delete(final T entity) { getCurrentSession().delete(entity); } public void deleteById(final Long entityId) { final T entity = findOne(entityId); delete(entity); } protected Session getCurrentSession() { return mysessionFactory.getCurrentSession(); } }
Concrete DAO
@Repository @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS,value="request") public class UserDAO extends AbstractHibernateDAO<User_Details_Pojo>{ }
-
beinghuman over 10 yearsplease go through my question once again.Wasn't expecting such an answer.Is my question unclear?Please let me know
-
Pratik Tari over 10 yearswe dont usually create service and dao objects for every request, neither do we need to create thread pools of these objects , although instantiating these two objects for every request wont slow down the process to much measurable extent unless they themselves have large dependencies to instantaite
-
beinghuman over 10 yearsokay i think I have missed something.by every request I mean those requests which needs to access something from database.For such situation definitely i cannot use singelton service and DAO object?
-
beinghuman over 10 yearsSuppose multiple users wants to register.I will create a registration bean(prototype,request,session scoped) for every user.Now I am passing this bean to Registration Service(annotated with @transactional annotation).This service will pass recieved registeration bean object to DAO.If service and DAO are singelton would'nt the requests be mixed up for multiple users?
-
beinghuman over 10 yearsSuppose multiple users wants to register.I will create a registration bean(prototype,request,session scoped) for every user.Now I am passing this bean to Registration Service(annotated with "@transactional" annotation).This service will pass recieved registeration bean object to DAO.If service and DAO are singelton would'nt the requests be mixed up for multiple users?
-
Olaf over 10 yearsThis should not happen unless you are trying to manage Hibernate sessions yourself in the DAOs. Spring would allocate a transactional context, including the Hibernate session, per thread. The web server would allocate a thread / grab a thread from the pool per each user's request. So the registration beans from two users would "live" in separate memory locations and would be processed via separate Hibernate sessions, and written to the database in the separate transactions on the separate DB connections.
-
beinghuman over 10 yearsThis will get clear if I you could explain me this.Multiple requests come.Web server allocates separate thread for each request.these threads uses same singleton controller which has prototype registerbean?how each thread will get separate model bean coz I have seen that if singelton controller uses prototype bean then during initialization of this singelton controller its dependent protype bean will also be created.So all requests will access single bean.Please enlighten me.
-
Nathan Hughes over 10 years@Nikhil: No. singleton services and daos are the default, and they work fine, as long as you don't have anything specific to an individual request in any of the instance members. Keep the request-specific stuff in method arguments and local variables, and Spring will handle the rest.
-
beinghuman over 10 years@NathanHughes Please check my comments in the answer of Olaf.Could you help me in understanding?
-
Sotirios Delimanolis over 10 years@NikhilArora The Registration bean you pass around is request scoped, ie it was created in a Controller handler method. Unless you give it to another thread, its scope will be restricted to the methods that operate on it. In other words, each time the DAO method is called, it will have a different
Registration
instance. There won't be any concurrency issues. -
Olaf over 10 yearsI wonder if the following would help you: stackoverflow.com/questions/3106452/…
-
beinghuman over 10 yearsI am very sorry to say that I still don't understand how My service layer would be stateless.Since it will carry different users' model objects and pass it to DAO ,I assume it would be statefull.ie prototype or request scope.either I have to use new keyword to create the service object and call the method which will hold the model bean ex:registerationService.registerUser(bean); or I f I am autowiring it in the controller, then I have to create a proxy of it.It would be great if you could help me out.
-
Olaf over 10 years@NikhilArora: I have hard time understanding what is the source of your confusion. Maybe you can explain what you mean when you say: "I will create a registration bean(prototype or request or session scoped) and autowire it in Controller". The registration bean should not be a member of the controller. You should create a registration bean for each request and then pass it to DAO.
-
Olaf over 10 years@Niks: I looked into alternative approaches (to what I normally do) for handling user sessions in Spring MVC, and it appears that if you want to use a session-scoped registration bean, your corresponding controller need to be request-scoped rather than being a sigleton.
-
beinghuman over 10 years@Olaf.Great Man.Thanks for still digging .I think this is not necessarily true.It depends upon design and I found the way to autowire session scoped bean into Singelton bean.you have to use either JDK or CGLIB Proxying.I used CGLIB Proxying because I had no Interaces.
-
theRiley over 7 yearsYes. Or to put it slightly differently, any singleton which is to be shared unaltered in a multi-threaded context must be -rendered- stateless by having any instance variables final, or constructor-loaded.