Scope of Controllers ,Service,Repository in Spring Web Application?

17,730

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.

Share:
17,730
beinghuman
Author by

beinghuman

Updated on July 26, 2022

Comments

  • beinghuman
    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
    beinghuman over 10 years
    please go through my question once again.Wasn't expecting such an answer.Is my question unclear?Please let me know
  • Pratik Tari
    Pratik Tari over 10 years
    we 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
    beinghuman over 10 years
    okay 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
    beinghuman over 10 years
    Suppose 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
    beinghuman over 10 years
    Suppose 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
    Olaf over 10 years
    This 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
    beinghuman over 10 years
    This 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
    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
    beinghuman over 10 years
    @NathanHughes Please check my comments in the answer of Olaf.Could you help me in understanding?
  • Sotirios Delimanolis
    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
    Olaf over 10 years
    I wonder if the following would help you: stackoverflow.com/questions/3106452/…
  • beinghuman
    beinghuman over 10 years
    I 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
    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
    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
    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
    theRiley over 7 years
    Yes. 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.