DAO类的spring singleton范围如何在内部工作

时间:2017-02-21 19:56:58

标签: spring dependency-injection

我浏览了一些关于Spring单例范围的博客和Spring文档,以及stackoverflow中几乎所有spring singleton和DAO相关的问题。 我仍然没有清楚地了解如何将相同的对象注入到依赖它的所有类中。我了解到DAO需要无状态

如果以下DAO(样本dao主要用于清除混淆的实例变量)类是使用默认的单例范围定义的,并且每次都注入相同的对象,则可能存在部门为空的情况,因此它不会获胜为部门值设置任何内容而不是使用之前的对象值。

public class UserDAO{

    int userId;
    Spring userDepartment;
    // getter setter methods for userId and userDepartment

   public boolean addUserToUserDetailsTable(int uId, 
                                            String name, String address, String department){
        // set userId
        userId = uId;

        if(department!=null)
           userDepartment = department;

       // write code to add user to user table
       // TO DO 


       // save user department data
       addUserToUserDepartmentTable(userId, userDepartment);
   }



   public void addUserToUserDepartmentTable(int uId, 
                                               String department){
        /* Code to save department data */
   }

}

因此,如果不使用 DI ,如果我使用new运算符手动调用DAO,则此问题不会出现。

new UserDAO()。addUserToUserDetailsTable(id," abc",null);

以上混淆会产生以下问题

  1. spring如何创建和注入singelton bean,它是否真的是唯一一个被注入所有调用类的对象。如果这是真的,那么如何重置DAO类上面的前一个对象值。

  2. 赢得实例变量在这里保存它们的值userId,userDepartment如果从多个类调用相同的对象?无状态意味着类不能有实例变量。

  3. spring内部使用new object()来注入bean。

  4. 或者它创建了一个DAO类的对象并创建了对象的多个克隆,我认为这是不可能的,因为DAO类没有实现clonnable。

  5. 请帮助我解决上述困惑。

3 个答案:

答案 0 :(得分:2)

  

spring如何创建和注入singelton bean,它是否真的是唯一一个被注入所有调用类的对象。

是的,它注入了DAO类的单个实例,总是相同的。这就是单身人士的定义:创建了一个单一实例。

  

如果这是真的,那么如何重置DAO类上面的前一个对象值。

它没有重置。

  

如果从多个类中调用相同的对象,那么实例变量不会在这里保存它们的值userId,userDepartment

是的,唯一实例将包含userId和department,因为这些是实例的字段。但是,您可能会遇到尝试读取和写入这些值的问题,因为它们构成了共享的可变状态,可以从多个线程同时访问而无需任何同步。

  

无状态意味着该类不能具有实例变量。

严格意义上说,是的。但DAO并不需要无国籍。它需要是线程安全的,因为同时从多个线程访问同一个实例。实现这一目标的最佳方法是避免任何状态(因此没有实例变量)。但是这对于DAO很难实现,DAO通常需要访问注入的DataSource,JdbcTemplate或EntityManager等等。但是,由于这些实例变量通常由Spring在启动期间注入,在DAO开始被多个线程使用之前,并且在应用程序的生命周期内从未写入,这是线程安全的。但是,您的代码具有状态,并且在应用程序的生命周期内修改状态,这使得它不安全。

  

spring内部使用new object()来注入bean。

这取决于如何声明DAO bean。它可以使用JavaConfig声明,使用调用构造函数的@Bean方法。大多数情况下,反射用于调用构造函数。因此代码中没有new MyDAO(),但仍然会调用构造函数(因为它是单例)只有一次,因为这是从头开始创建对象实例的唯一方法。

  

或者它创建了一个DAO类的对象并创建了对象的多个克隆,我认为这是不可能的,因为DAO类没有实现clonnable。

如果这样做,就不会是单身人士。

答案 1 :(得分:2)

Spring中的Singleton范围bean意味着每个容器一个实例,并且bean必须是无状态的,否则在多线程方案的情况下会遇到问题。

  

春天如何创造和注入singelton豆,是不是真的           一个且只有一个被注入所有调用类的对象。

Spring在启动时创建一次实例,并将相同的引用传递给所有通过依赖注入请求相同的调用对象。

  

如果这是真的那么前面的对象如何从DAO上面估值   类被重置。

如果你的bean是无状态的,那么对象就没有值,因为大多数变量都是方法本地的,而不是绑定到Instance对象(在本例中是DAO类)。但是在你的情况下,因为你有成员变量绑定到一个类 获取此DAO bean的所有类都将看到设置为成员变量的相同值,并且此数据将被破坏,不建议这样做。

  

实例变量不会在这里保存它们的值userId,   userDepartment如果从多个类调用相同的对象??   无状态意味着类不能有实例变量。

是的,这是bean无状态的确切定义。如上所述。

  

spring内部使用new object()来注入bean。或它   创建一个DAO类的对象,并创建多个克隆   对象,我认为这是不可能的,因为DAO类不是   实施clonnable。

如果你还没有定义bean范围,默认情况下spring会假设它是Singleton。单身范围和单身模式的理解是不同的。 Spring仅通过提供实例来模仿单例模式,但这并不能阻止您创建新实例(使用say new operator)。

答案 2 :(得分:1)

你的单身人士不是无国籍人。 Userid和Department定义'state'。

Spring使用反射'newInstance'或配置中的生产者函数创建一个实例。

然后将这一个实例提供给请求DAO的所有对象。

您的注意事项全部有效但春季未解决:由于您的DAO处于状态,因此未正确实施且结果未定义。

回答问题1:没有重置。 Spring不会为你处理状态!

基本上(Q2)如果在无状态bean中使用实例变量,则处于危险的路径上。与其他DAO单身人士一样,实例变量本身也需要无国籍。

更新:我想详细说明这一点。单例可以具有状态,但是DAO的所有用户之间共享状态。这并不严格要求您的DAO是线程安全的:如果您不使用线程,则没有并发使用 - 但是单例的状态是共享状态:单例的所有用户都具有相同的状态。如果你有两个这样的函数:

@Component
public class A {
    @Autowired
    DaoObject singleton;

    @Autowired
    B another;

    public void aFunctionA() {
        singleton.userId = "Foo";
        System.out.printf("UserId: %s%n", singleton.userId); // prints Foo
        another.aFunctionB();
        System.out.printf("UserId: %s%n", singleton.userId); // prints Serviceuser
   }
}


@Service
public class B {
    @Autowired
    DaoObject singleton;

    public void aFunctionB() {
        singleton.userId = "Serviceuser";
   }
}

单身singleton的状态在班级的所有用户之间共享。如果一个类改变状态,则所有其他用户必须处理该状态。

如果您正在使用线程,则会增加有状态单例的额外复杂性,因为您对状态的修改必须是线程安全的。 通常的做法是在初始化后保持单例不可变。

关于你的第四个问题:Spring不会克隆一个Singleton,如上所述。