spring怎么实现单例模式?

Spring通过单例注册表的方式实现单例模式,即检查内部map中是否存在实例,不存在时才同步创建,以此保证线程安全。

参考https://www.cnblogs.com/nickup/p/9800120.html

那么Spring对单例的底层实现,到底是饿汉式单例还是懒汉式单例呢?呵呵,都不是。Spring框架对单例的支持是采用单例注册表的方式进行实现的,

其实就是检查map里面由没有,没有则创建

当然 检查和创建都需要同步

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

 

<think>好的,我需要回答用户关于单例模式使用时需要注意的问题。首先,根据用户提供的引用资料,单例模式主要有饿汉式和懒汉式两种实现方式,每种都有其优缺点和注意事项。我需要将这些信息整理出来,并确保回答结构清晰,符合用户的要求。 首先,用户提到的引用[1]和[4]详细说明了饿汉式和懒汉式的区别。饿汉式在类加载时就创建实,线程安全但可能浪费资源;懒汉式延迟加载,但需要考虑线程安全问题。引用[3]和[5]给出了双重检查锁定的实现方法,并提到volatile关键字的重要性。引用[4]还讨论了资源利用率和性能问题。这些都需要涵盖在注意事项中。 接下来,我需要组织这些点,确保每个问题都明确列出。如,线程安全是懒汉式的关键点,必须用双重检查锁和volatile来避免问题。序列化和反射攻击也是潜在问题,引用资料中没有直接提到,但根据我的知识,单例模式在序列化时可能被破坏,可以通过实现readResolve方法解决。反射攻击则需要防止通过反射调用构造函数,这可以通过在构造器中抛出异常来实现。此外,单例模式可能违反一职责原则,这也是引用[1]提到的一个坏处。 另外,用户提供的引用[4]提到资源利用率和性能,需要指出饿汉式可能影响启动时间,而懒汉式虽然节省资源但可能增加复杂性。还有,单例模式不适合有继承需求的场景,因为构造函数是私有的,这也是需要注意的地方。 最后,生成相关问题,参考用户之前的子,问题应该围绕单例模式实现、线程安全、优缺点、应用场景等方面。需要确保问题相关且有深度,帮助用户进一步理解。 总结时,要分点列出注意事项,每个点结合引用资料和补充知识,同时保持语言自然,符合中文习惯。还要检查是否遵循了系统级指令,比如数学表达式是否正确使用$...$,但这里可能不需要数学公式。确保引用标识正确添加,如关于线程安全的部分引用[3][4][5],资源管理引用[1][4]等。</think>### 单例模式使用注意事项及潜在问题 单例模式虽然能有效管理全局唯一实,但在实际使用中需注意以下关键问题: --- #### 1. **线程安全性(懒汉式重点)** - **问题**:懒汉式(延迟加载)在多线程环境下可能因并发调用导致多次实化,破坏唯一性。 - **解决方案**: - 使用**双重检查锁定(Double-Checked Locking)**,并通过`volatile`关键字禁止指令重排序(避免返回未初始化完成的对象)[^3][^5]。 - 或改用**静态内部类**实现延迟加载(利用类加载机制保证线程安全)。 ```java public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { if (instance == null) { // 第二次检查 instance = new Singleton(); } } } return instance; } } ``` --- #### 2. **资源利用率与初始化时机** - **饿汉式**:类加载时即初始化实,可能占用未使用资源,影响启动速度[^4]。 - **懒汉式**:延迟加载节省资源,但首次访问时可能因初始化耗时导致性能波动(如数据库连接池)[^4]。 --- #### 3. **序列化与反序列化破坏** - **问题**:若实现`Serializable`接口,反序列化时会创建新实。 - **解决方案**: - 重写`readResolve()`方法返回现有实: ```java protected Object readResolve() { return getInstance(); } ``` --- #### 4. **反射攻击** - **问题**:通过反射调用私有构造函数可创建新实。 - **防御方法**:在构造器中添加检查,若实已存在则抛出异常: ```java private Singleton() { if (instance != null) { throw new IllegalStateException("类禁止反射构造!"); } } ``` --- #### 5. **设计原则与扩展性** - **一职责原则**:类可能承担过多职责(如管理资源+业务逻辑),导致代码臃肿[^1]。 - **扩展性限制**:类无法通过继承扩展(构造函数私有),需通过组合或依赖注入改进[^1][^4]。 --- #### 6. **测试与依赖耦合** - **问题**:作为全局状态,可能导致测试困难(如无法隔离不同测试用的影响)。 - **改进方向**:使用依赖注入框架(如Spring)管理生命周期,降低耦合度。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值