【问题标题】:Scope of Controllers ,Service,Repository in Spring Web Application?Spring Web应用程序中控制器,服务,存储库的范围?
【发布时间】:2013-09-03 05:53:34
【问题描述】:

我正在使用 spring、hibernate 创建一个 Web 应用程序。 假设多个用户想要注册。我将创建一个注册 bean(原型或请求或会话范围)并在 Controller 中自动装配它。

现在我将此 bean 传递给注册服务(使用“@transactional”注释进行注释),该服务也在控制器中自动装配。 此服务会将收到的注册 bean 对象传递给 DAO(此 DAO 是在服务中自动装配的)如果服务和 DAO 是单一的,多个用户的请求不会混淆吗?

这是我所做的:我将服务范围和 DAO 创建为“请求”。 这是正确的方法吗?或者我还能做些什么来制作服务和 DAO singelton?

我的请求范围背后的逻辑: 将服务和 DAO 作为请求范围的原因是如果多个用户调用 注册服务.registerUser(bean);同时来自控制器并且范围是单例的,那么就没有一致性,因为有一个对象的方法被不同的输入调用。

让我知道我哪里错了。

注册 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


}

控制器

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



            }



        }

道:

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();
    }
}

具体的 DAO

@Repository
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS,value="request")
public class UserDAO extends AbstractHibernateDAO<User_Details_Pojo>{


}

【问题讨论】:

    标签: java multithreading spring hibernate spring-mvc


    【解决方案1】:

    服务和 DAO 应该是无状态的。这将允许您将它们配置为 Spring 单例。我希望这就是您所说的“单例”的意思。

    所有线程问题,包括线程池,都将由基础架构处理:您的 Web/Java EE 服务器和 Spring DI。

    【讨论】:

    • 假设多个用户想要注册。我将为每个用户创建一个注册 bean(原型、请求、会话范围)。现在我将这个 bean 传递给注册服务(使用“@transactional”注释进行注释).此服务会将收到的注册 bean 对象传递给 DAO。如果服务和 DAO 是单一的,那么多个用户的请求不会混淆吗?
    • 这不应该发生,除非您尝试自己在 DAO 中管理 Hibernate 会话。 Spring 将为每个线程分配一个事务上下文,包括 Hibernate 会话。 Web 服务器将根据每个用户的请求分配一个线程/从池中获取一个线程。因此,来自两个用户的注册 bean 将“存在”在不同的内存位置,并通过单独的 Hibernate 会话进行处理,并在单独的 DB 连接上的单独事务中写入数据库。
    • 如果我能解释一下,这会很清楚。多个请求来了。Web 服务器为每个请求分配单独的线程。这些线程使用具有原型 registerbean 的相同单例控制器?每个线程将如何分开模型bean因为我已经看到如果singelton控制器使用原型bean,那么在这个singelton控制器的初始化过程中,它的依赖原型bean也会被创建。所以所有请求都将访问单个bean。请赐教。
    • 不知道以下内容是否对您有帮助:stackoverflow.com/questions/3106452/…
    • 很抱歉我还是不明白我的服务层怎么会是无状态的。由于它会携带不同用户的模型对象并传递给DAO,我假设它是有状态的.ie 原型或请求范围。要么我必须使用 new 关键字来创建服务对象并调用将保存模型 bean 的方法 ex:registerationService.registerUser(bean);或者如果我在控制器中自动装配它,那么我必须创建它的代理。如果你能帮助我,那就太好了。
    【解决方案2】:

    使用 @Service 注释您的服务类,使用 @Repository 注释 Dao 类。

    <context:component-scan base-package="x.y.z.service, x.y.z.dao" /> 
    

    它会自动为你的类创建单例 bean

    【讨论】:

      【解决方案3】:

      除非您的 DAO 需要实例字段,否则无需将它们设置为请求范围。只要使用线程绑定的Session#getCurrentSession() 检索您的Hibernate Session,就可以使用单个DAO 实例来处理所有请求。这同样适用于服务类和控制器。

      至于你的说法

      我认为这会减慢对用户的响应

      这并不总是正确的,这取决于物体的重量。 Servlet 容器和您的 Spring DispatcherServlet 无论如何都会实例化这么多对象。你不应该看到很大的变化。

      创建一个包含这些对象的池将是矫枉过正。注意:那些不是线程池,只是对象池。

      【讨论】:

      • 假设多个用户想要注册。我将为每个用户创建一个注册 bean(原型、请求、会话范围)。现在我将此 bean 传递给注册服务(使用 @transactional 注释进行注释)。此服务会将接收到的注册 bean 对象传递给 DAO。如果服务和 DAO 是单例的,那么多个用户的请求不会混淆吗?
      • @Nikhil:不,单例服务和 daos 是默认设置,只要您在任何实例成员中没有特定于单个请求的任何内容,它们就可以正常工作。将特定于请求的内容保存在方法参数和局部变量中,其余部分由 Spring 处理。
      • @NathanHughes 请在 Olaf 的回答中检查我的 cmets。您能帮我理解一下吗?
      • @NikhilArora 您传递的注册 bean 是请求范围的,即它是在控制器处理程序方法中创建的。除非你把它交给另一个线程,否则它的范围将被限制在对其进行操作的方法上。换句话说,每次调用 DAO 方法时,都会有一个不同的Registration 实例。不会有任何并发​​问题。
      【解决方案4】:

      您应该使用 spring 将您的服务、dao 对象注入到您的控制器中,并且所有通过 spring 注入的 bean 默认情况下都是单例

      【讨论】:

      • 请再次检查我的问题。没想到会有这样的答案。我的问题不清楚吗?请告诉我
      • 我们通常不会为每个请求创建 service 和 dao 对象,我们也不需要创建这些对象的线程池,尽管为每个请求实例化这两个对象不会在很大程度上减慢进程,除非他们自己对实例化有很大的依赖关系
      • 好吧,我想我错过了一些东西。每一个请求我的意思是那些需要从数据库访问某些东西的请求。对于这种情况,我绝对不能使用单格顿服务和 DAO 对象?
      【解决方案5】:

      但是,在阅读了所有链接之后,我也遇到了同样的困惑。 这就是我所理解的(如果我错了请纠正我) 注册 bean 将是原型或请求类型,因为可以同时有两个或多个注册请求,如果该对象是单例的,那么将覆盖彼此的值。

      DAO 和服务将是单例的,因为它们只是方法,不会修改其他线程要使用的任何全局变量。他们有自己的堆栈。

      【讨论】:

      • 是的。或者稍微不同地说,任何要在多线程上下文中原样共享的单例都必须通过使任何实例变量最终或构造函数加载来实现无状态渲染。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-25
      • 2011-04-03
      • 1970-01-01
      • 1970-01-01
      • 2016-05-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多