2017-02-21 38 views
0

我翻阅了一些关于Spring单例作用域的博客和spring文档,以及几乎所有的spring单例和DAO相关的问题。 我仍然不清楚如何将相同的对象注入到所有依赖它的类中。我已经了解到DAO需要为无状态DAO类的spring单例作用域如何在内部工作

如果下面的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,如果我手动调用DAO使用新的运营商这个问题不会在那里。

new UserDAO()。addUserToUserDetailsTable(id,“abc”,null);

上述混乱产生以下问题

  1. 如何春季创建和注入singelton豆,是不是真的有且只有一个它获取注入到所有调用的类对象。如果这是真的,那么重置DAO类之前的对象值的方式。

  2. 不会将实例变量的值保存在这里userId,userDepartment是否从多个类中调用同一个对象?无状态意味着类不能有实例变量。

  3. 是否在内部使用new object()来注入bean。

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

请帮我解决上面的困惑。

回答

2

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

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

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

它没有重置。

不会将实例变量的值保存在这里userId,userDepartment是否从多个类中调用同一个对象?

是的,唯一的实例将保存userId和department,因为这些是实例的字段。不过,您可能会遇到尝试读取和写入这些值的问题,因为它们构成共享的可变状态,可以在不同步的情况下从多个线程同时访问这些状态。

无状态是指类不能有实例变量。

从严格意义上说,是的。但是DAO不需要是无状态的。它需要是线程安全的,因为同时从多个线程访问同一个实例。实现这一点的最好方法是避免有任何状态(所以没有实例变量)。但是对于一个DAO来说,这很难实现,DAO通常需要访问JdbcTemplate或EntityManager的注入数据源,或者其他任何东西。但是,由于这些实例变量通常在启动期间由Spring注入,所以在DAO开始被多个线程使用之前,并且在应用程序的生命周期中从不写入,这是线程安全的。但是,您的代码具有状态,并且状态在应用程序的生命周期中被修改,这使得它不安全。

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

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

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

这不会是一个单身人士,如果它这样做。

1

你的单身并不是无国籍的。 Userid和Department定义'状态'。

Spring在您的配置中使用反射'newInstance'或生成器函数创建一个实例。

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

您的注意事项都是有效的,但并未由spring解决:由于您的DAO具有状态,因此未正确实施并且结果未定义。

对问题1的回答:未重置。春天不会为你处理状态!

基本上(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的状态类的所有用户之间共享。如果一个班级改变了状态,所有其他用户都必须应对。

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

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

+0

您的示例代码有意义...谢谢。 – cjava

2

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

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

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

如果这是真的,那么如何重置DAO 类以前的对象值。

如果你的bean是无状态的,那么这个对象将没有任何值,因为大部分变量都是局部方法,并且不绑定到Instance对象(在这种情况下是DAO类)。然而,在你的情况下,因为你的成员变量绑定到一个类 所有获得这个DAO bean的类将看到相同的值设置成员变量,这些数据将被破坏,不建议。

如果将同一对象从多个类调用不是实例变量在这里举行他们的价值观用户id, userDepartment? 无状态意味着类不能有实例变量。

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

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

如果您还没有定义bean作用域,默认情况下spring会认为它是Singleton。单身人士范围和单身人士模式的理解是不同的。 Spring通过仅提供实例来模拟单例模式,但这并不能阻止您创建新实例(使用new运算符)。

相关问题