`

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与单例模式的区别,通过对比两者的定义、实现机制和应用场景,帮助读者更好地理解这两种概念的异同。 一、单例模式的定义和实现 单例模式是一...

    单例模式详解 1. 什么是单例模式? 1.1 单例模式的核心要素 1.2 为什么需要单例模式? 2. 单例模式的实现方式 2.1 饿汉式(静态常量) 2.2 饿汉式(静态代码块) 2.3 懒汉式(线程

    单例模式详解 1. 什么是单例模式? 1.1 单例模式的核心要素 1.2 为什么需要单例模式? 2. 单例模式的实现方式 2.1 饿汉式(静态常量) 2.2 饿汉式(静态代码块) 2.3 懒汉式(线程不安全) 2.4 懒汉式(线程安全,...

    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编程中被广泛使用,尤其是在需要控制实例化过程,确保一个类只有一个实例时。这个模式的主要目的是限制类的实例化次数,提供全局唯一的访问点,同时可能对性能和...

Global site tag (gtag.js) - Google Analytics