`

Spring的单例模式

阅读更多
单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例。
单例模式有以下的特点:

单例类只能有一个实例

单例类必须自己创建自己的唯一实例

单例类必须给所有其他对象提供这一实例

下面我们就来写一个简单的单例模式的例子:
Public class Singleton1{
Private static final Singleton1 instance=new Singleton1();
//私有的默认构造函数
Public Singleton1(){}
//静态工厂方法
Public static Singleton1 getInstance(){
    Return instance;
}
} 
大家可以看出来,在这个类被加载时,静态变量instance会被初始化,此时该类的私有构造函数被调用,这时候,单例类的唯一实例就被创建出来了

值得注意的是:由于构造函数是私有的,因此该类不能被继承

还有一种写法也可以实现单例模式:
Public class Singleton2{
   Private static final Singleton2 instance=null;
   //私有的默认构造函数
   Public Singleton1(){}
   //静态工厂方法
   Public synchronized static Singleton2 getInstance(){
     If(instance==null){
       Instance=new Singleton2();
     }
     Return instance;
   }
} 

这种写法和第一种的区别在于:实例并没有直接实例化,而是在静态工厂方法被调用的时候才进行的,而且对静态工厂方法使用了同步化,以处理多线程并发的环境。
这两种写法还有两个非常有意思的名字:第一种称为饿汉式单例,第二种称为懒汉式单例。至于为什么起这个名字,自己好好想想吧。
饿汉式单例在自己被加载时就将自己实例化,如果从资源利用效率角度来讲,比懒汉式单例类稍差些。但是从速度和反应时间角度来讲,则比懒汉式要稍好些。

但是遗憾的是:懒汉式单例类也不能被继承

我们克服前两种单例类不能被继承的缺点,我们可以使用另外一种特殊化的单例模式,它被称为单例注册表。
Import java.util.HashMap;
Public class RegSingleton{
   Static private HashMap registry=new HashMap();
   //静态块,在类被加载时自动执行
    Static{
     RegSingleton rs=new RegSingleton();
     Registry.put(rs.getClass().getName(),rs);
   }
//受保护的默认构造函数,如果为继承关系,则可以调用,克服了单例类不能为继承的缺点
Protected RegSingleton(){}
//静态工厂方法,返回此类的唯一实例
public static RegSingleton getInstance(String name){
    if(name==null){
      name=” RegSingleton”;
    }if(registry.get(name)==null){
      try{
          registry.put(name,Class.forName(name).newInstance());
       }Catch(Exception ex){ex.printStackTrace();}
    }
    Return (RegSingleton)registry.get(name);
}
} 
 
下面我们来看看Spring中的单例实现,当我们试图从Spring容器中取得某个类的实例时,默认情况下,Spring会才用单例模式进行创建。
<bean id="date" class="java.util.Date"/>
<bean id="date" class="java.util.Date" scope="singleton"/> (仅为Spring2.0支持)
<bean id="date" class="java.util.Date" singleton="true"/>

以上三种创建对象的方式是完全相同的,容器都会向客户返回Date类的单例引用。那么如果我不想使用默认的单例模式,每次请求我都希望获得一个新的对象怎么办呢?很简单,将scope属性值设置为prototype(原型)就可以了

<bean id="date" class="java.util.Date" scope="prototype"/>

通过以上配置信息,Spring就会每次给客户端返回一个新的对象实例。

那么Spring对单例的底层实现,到底是饿汉式单例还是懒汉式单例呢?呵呵,都不是。Spring框架对单例的支持是采用单例注册表的方式进行实现的,源码如下:
public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{
   /**
    * 充当了Bean实例的缓存,实现方式和单例注册表相同
    */
   private final Map singletonCache=new HashMap();
   public Object getBean(String name)throws BeansException{
       return getBean(name,null,null);
   }
...
   public Object getBean(String name,Class requiredType,Object[] args)throws BeansException{
      //对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或则做转码)
      String beanName=transformedBeanName(name);
      Object bean=null;
      //手工检测单例注册表
      Object sharedInstance=null;
      //使用了代码锁定同步块,原理和同步方法相似,但是这种写法效率更高
      synchronized(this.singletonCache){
         sharedInstance=this.singletonCache.get(beanName);
       }
      if(sharedInstance!=null){
         ...
         //返回合适的缓存Bean实例
         bean=getObjectForSharedInstance(name,sharedInstance);
      }else{
        ...
        //取得Bean的定义
        RootBeanDefinition mergedBeanDefinition=getMergedBeanDefinition(beanName,false);
         ...
        //根据Bean定义判断,此判断依据通常来自于组件配置文件的单例属性开关
        //<bean id="date" class="java.util.Date" scope="singleton"/>
        //如果是单例,做如下处理
        if(mergedBeanDefinition.isSingleton()){
           synchronized(this.singletonCache){
            //再次检测单例注册表
             sharedInstance=this.singletonCache.get(beanName);
             if(sharedInstance==null){
                ...
               try {
                  //真正创建Bean实例
                  sharedInstance=createBean(beanName,mergedBeanDefinition,args);
                  //向单例注册表注册Bean实例
                   addSingleton(beanName,sharedInstance);
               }catch (Exception ex) {
                  ...
               }finally{
                  ...
              }
             }
           }
          bean=getObjectForSharedInstance(name,sharedInstance);
        }
       //如果是非单例,即prototpye,每次都要新创建一个Bean实例
       //<bean id="date" class="java.util.Date" scope="prototype"/>
       else{
          bean=createBean(beanName,mergedBeanDefinition,args);
       }
}
...
   return bean;
}
} 
 
以上的源码对于很多同学来说,可能感觉比较恐怖,但是学习要学会抓住要领,刚才的源码中,大家真正要记住的是Spring对bean实例的创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是HashMap对象,如果配置文件中的配置信息不要求使用单例,Spring会采用新建实例的方式返回对象实例
分享到:
评论

相关推荐

    浅谈Spring单例Bean与单例模式的区别

    "浅谈Spring单例Bean与单例模式的区别" 本文主要介绍了Spring单例Bean与单例模式的区别,通过对比两者的定义、实现机制和应用场景,帮助读者更好地理解这两种概念的异同。 一、单例模式的定义和实现 单例模式是一...

    spring单例引起的线程安全问题

    【Spring 单例模式与线程安全】 在 Spring 框架中,bean 的实例化策略分为两种:单例(Singleton)和多例(Prototype)。单例模式意味着在整个 Spring 容器中,对于一个给定的 bean 定义,只会存在一个实例。这通常...

    大话设计模式--Singleton(单例模式)

    例如,Spring框架中的ApplicationContext就是通过单例模式来管理所有bean的。然而,需要注意的是,过度使用单例可能导致系统设计过于紧密,不利于测试和扩展,因此在设计时应权衡利弊。 总之,单例模式是一种常用的...

    单例多例模式

    在Spring框架中,默认情况下是单例模式。如果要产生多例,则需要在配置文件的bean中添加scope="prototype"。这将告诉Spring框架为每个请求创建一个新的对象实例。 三、为什么要用单例多例? 单例模式的优点是能够...

    简单工厂,代理模式,单例模式demo

    而Spring的单例Bean管理,正是单例模式的体现。 总结来说,简单工厂、代理和单例模式是软件设计中的基础工具,它们帮助我们更好地组织代码,提高代码的可复用性和可维护性。理解和掌握这些模式,对于提升编程技能和...

    单例模式的七种写法

    单例模式是软件设计模式中的一种经典模式,用于确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下都非常有用,比如控制数据库连接、管理缓存或者全局配置等。下面我们将详细探讨单例模式的七种...

    常见设计模式-单例模式

    在Spring框架中,单例模式的实现主要依赖于IoC容器。Spring通过`singletonObjects`、`earlySingletonObjects`和`singletonFactories`三级注册表来管理单例对象,依次尝试从这三个层次获取单例。这种方式既实现了单例...

    设计模式之单例模式

    单例模式是软件设计模式中的一种经典模式,它在许多实际场景中被广泛使用,尤其在需要...同时,随着编程语言和框架的发展,如Spring框架中的依赖注入,有时可以避免使用单例模式,通过更灵活的方式管理对象的生命周期。

    Java单例模式应用研究.pdf

    Java的Struts、Spring框架,.Net的Spring.Net框架,以及PHP的Zend框架都大量使用了单例模式。 单例模式在实际应用中非常广泛,但对Java程序员来说,设计好单例模式却是一个复杂的过程。在开发中,我们可以根据面向...

    懒汉式单例模式的实现案例

    单例模式的特点:从系统启动到终止,整个过程只会产生一个实例。因为单例提供了唯一实例的全局访问...单例模式常见的应用场景如下:Windows任务管理器、数据库连接池、Java中的Runtime、Spring中Bean的默认生命周期等。

    java之单例模式

    通过Spring的配置文件或者注解来实现单例模式。代码示例如下: ```java @Component @Scope("singleton") public class Singleton { // ... } ``` #### 四、单例模式的应用场景 - **系统配置管理**:对于...

    Android单例模式

    登记式单例模式通常用于需要注册多个单例对象的场景,如Spring框架中的Bean注册。 ##### 实现代码示例 ```java public class Singleton3 { private static Map, Singleton3&gt; map = new HashMap(); private ...

    单例模式demo

    单例模式是软件设计模式中的一种,用于控制类的实例化过程,确保一个类在整个程序运行期间只有一个实例存在。在Java或Android开发中,单例模式被广泛应用,特别是在需要全局共享资源或者对象的情况下,比如数据库...

    2.单例模式(Singleton)1

    - Spring的Bean:Spring框架中的Bean默认就是单例模式。 **模式的优点和缺点** 优点: 1. 节约系统资源,避免创建不必要的对象。 2. 减少对象的创建和销毁开销,提高效率。 3. 在并发环境中,避免对共享资源的多次...

    Java 单例模式线程安全问题

    在 Spring 框架中,单例模式是默认的作用域,即在整个应用程序生命周期中,只有一个实例存在。为了确保线程安全,Spring 使用 ThreadLocal 来处理一些非线程安全的状态。例如,RequestContextHolder、...

    JAVA单例模式的几种实现方法

    登记式单例模式通常用于类似于Spring框架中的bean管理方式,即在单例类中维护一个容器或注册表,将类名及其对应的实例注册进去,之后可以通过查询注册表来获取相应的单例实例。 ##### 代码示例: ```java import ...

    MVC(单例模式)设计模式

    随着技术的发展,现代框架如Spring MVC提供了更全面的MVC支持,简化了开发过程,同时也提供了更多设计模式的集成,如依赖注入(Dependency Injection)和面向切面编程(Aspect-Oriented Programming)。 总之,MVC...

    讲解JAVA设计模式中的单例模式

    单例模式是软件设计模式中的一种经典模式,它在Java编程中被广泛使用,尤其是在需要控制实例化过程,确保一个类只有一个实例时。这个模式的主要目的是限制类的实例化次数,提供全局唯一的访问点,同时可能对性能和...

    41丨单例模式(上):为什么说支持懒加载的双重检测不比饿汉式更优?1

    【单例模式】是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点。单例模式的主要目的是控制类的实例化过程,确保在任何情况下,对于特定类,都只有一个对象存在。这样的设计通常用于资源管理,比如...

Global site tag (gtag.js) - Google Analytics