Spring学习笔记 关于Spring创建Bean的模式-Singleton(单例模式)和Prototype

本文通过测试代码深入解析Spring中的Bean单例模式。Spring的单例模式并不完全等同于传统设计模式中的单例,它确保每个Spring Container中定义的Bean只有一个实例,每个Bean定义也仅存在一个实例。在不同Container中获取相同定义的Bean,或在同一Container中通过不同引用获取Bean,可能会创建不同的实例。此外,通过`scope="prototype"`可以改变Bean的创建模式,使其每次请求时创建新实例。
摘要由CSDN通过智能技术生成

刚开始接触Spring的时候一些基础的教学在说到Bean的创建时会提到Spring的单例模式,就是说默认情况下Spring中定义的Bean是以单例模式创建的。如果以前了解设计模式中的单例模式的话很容易对这种说法产生先入为主的印象。事实上,Spring中的单例模式还有许多需要注意的地方。

在GoF中的单例模式是指一个ClassLoader中只存在类一个实例。

而在Spring中的单例实际上更确切的说应该是:
1.每个Spring Container中定义的Bean只存在一个实例
2.
每个Bean定义只存在一个实例。
 

如果对Spring的单例模式不够了解在设计与开发过程中会留下很多隐患。以下是根据Spring中单例模式的特点写的测试代码,通过代码可以更直观的了解Spring中的单例模式。

先看一下这个测试中用到的类已经XML中Bean的定义.随后给出Main方法中的测试代码:

 

根据以上类定义,执行以下main方法进行测试:

  1. package beanscope;  
  2.   
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. public class BeanScopceMain  
  7. {  
  8.   
  9.     /** 
  10.      * @comment [注释说明] 
  11.      * @author 荣磊, 2012-7-17 
  12.      *  
  13.      * @param args 
  14.      */  
  15.     public static void main(String[] args)  
  16.     {  
  17.         String springConfig = "beanscope/spring-config.xml";  
  18.         //创建一个SpringContainer   
  19.         ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);  
  20.           
  21.         //通过SpringContainer取得runnerBeanOne   
  22.         RunnerBeanRefToSingletonBean runnerBeanOne =   
  23.                context.getBean("runnerBeanOne", RunnerBeanRefToSingletonBean.class);  
  24.         //通过SpringContainer取得runnerBeanTwo   
  25.         RunnerBeanRefToSingletonBeanTwo runnerBeanTwo =   
  26.                context.getBean("runnerBeanTwo", RunnerBeanRefToSingletonBeanTwo.class);    
  27.         //通过SpringContainer取得singletonBean   
  28.         SingletonBean singletonBean =   
  29.                context.getBean("singletonBean", SingletonBean.class);        
  30.           
  31.         //输出上一次操作singltonBean的Bean名称,   
  32.         //因为在这之前没有对singletonBean的lastOperatedBy属性进行初始化,所以这里应该会输出none   
  33.         singletonBean.showLastOperateBean();  
  34.           
  35.         //设置runnerBeanOne中singletonBean对象的上一次操作者信息为runnerBeanOne   
  36.         runnerBeanOne.setMyNameToSingletonBean();  
  37.         //通过singletonBean输出上一次操作者信息   
  38.         singletonBean.showLastOperateBean();  
  39.         //输出runnerBeanTwo中应用的singletonBean对象的上一次操作者信息   
  40.         runnerBeanTwo.showLastOprBeanOfSingletonBean();  
  41.           
  42.        //设置runnerBeanOne中singletonBean对象的上一次操作者信息为runnerBeanTwo   
  43.        runnerBeanTwo.setMyNameToSingletonBean();  
  44.        //通过singletonBean输出上一次操作者信息   
  45.         singletonBean.showLastOperateBean();  
  46.        //输出runnerBeanOne中应用的singletonBean对象的上一次操作者信息   
  47.         runnerBeanOne.showLastOprBeanOfSingletonBean();  
  48.     }  
  49.   
  50. }  
package beanscope;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopceMain
{

    /**
     * @comment [注释说明]
     * @author 荣磊, 2012-7-17
     * 
     * @param args
     */
    public static void main(String[] args)
    {
        String springConfig = "beanscope/spring-config.xml";
        //创建一个SpringContainer
        ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
        
        //通过SpringContainer取得runnerBeanOne
        RunnerBeanRefToSingletonBean runnerBeanOne = 
               context.getBean("runnerBeanOne", RunnerBeanRefToSingletonBean.class);
        //通过SpringContainer取得runnerBeanTwo
        RunnerBeanRefToSingletonBeanTwo runnerBeanTwo = 
               context.getBean("runnerBeanTwo", RunnerBeanRefToSingletonBeanTwo.class);  
        //通过SpringContainer取得singletonBean
        SingletonBean singletonBean = 
               context.getBean("singletonBean", SingletonBean.class);      
        
        //输出上一次操作singltonBean的Bean名称,
        //因为在这之前没有对singletonBean的lastOperatedBy属性进行初始化,所以这里应该会输出none
        singletonBean.showLastOperateBean();
        
        //设置runnerBeanOne中singletonBean对象的上一次操作者信息为runnerBeanOne
        runnerBeanOne.setMyNameToSingletonBean();
        //通过singletonBean输出上一次操作者信息
        singletonBean.showLastOperateBean();
        //输出runnerBeanTwo中应用的singletonBean对象的上一次操作者信息
        runnerBeanTwo.showLastOprBeanOfSingletonBean();
        
       //设置runnerBeanOne中singletonBean对象的上一次操作者信息为runnerBeanTwo
       runnerBeanTwo.setMyNameToSingletonBean();
       //通过singletonBean输出上一次操作者信息
        singletonBean.showLastOperateBean();
       //输出runnerBeanOne中应用的singletonBean对象的上一次操作者信息
        runnerBeanOne.showLastOprBeanOfSingletonBean();
    }

}

 

输出结果:

从这个执行结果来看已经可以看出单例模式的影子,两个分别创建的runnerBean对象在定义中都依赖于singletonBean对象,第2步中,使用runnerBeanOne.setMyNameToSingletonBean()方法,设置了runnerBeanOne自己引用的singletonBean的操作者信息,随后输出了runnerBeanTwo自己引用的singletonBean和单独创建的singletonBean的操作者信息,结果都是runnerBeanOne,这就说明,当runnerBeanOne操作自己引用的singletonBean时,对runnerBeanTwo中和单独创建的singletonBean产生了影响,也就是他们所引用的singletonBean对象是同一个对象。

这是因为runnerBeanOne与runnerBeanTwo在Spring定义Bean时都设置了一个property ref引用到了同一个singletonBean的Bean定义。 这就是最前面说道的两点中的第二点:2.每个Bean定义只存在一个实例。 如果在Spring配置文件中定义runnerBeanOne与runnerBeanTwo时引用到不同的singletonBean定义,就会创建出两个不同的singletonBean对象,即使两个Bean定义实际上对应的class是相同的。如下:

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  5.       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值