隨筆-61  評論-13  文章-19  trackbacks-0

          單例模式也屬于創建型模式,所謂單例,顧名思義,所指的就是單個實例,也就是說要保證一個類僅有一個實例。
                            單例模式有以下的特點:
                            ①
                            單例類只能有一個實例
                            ②
                            單例類必須自己創建自己的唯一實例
                            ③
                            單例類必須給所有其他對象提供這一實例
                            下面我們就來寫一個簡單的單例模式的例子:
                            Public class Singleton1{
                            Private static final Singleton1 instance=new Singleton1();
                            //私有的默認構造函數
                            Private 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會采用新建實例的方式返回對象實例

          posted on 2010-01-21 09:52 xnabx 閱讀(1724) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 肇源县| 庄浪县| 崇礼县| 桦南县| 新和县| 江阴市| 齐河县| 建水县| 大邑县| 平凉市| 项城市| 遂昌县| 鄯善县| 自治县| 菏泽市| 柘城县| 河西区| 深圳市| 新乐市| 井研县| 克拉玛依市| 平遥县| 郴州市| 环江| 湖州市| 广宁县| 密云县| 上杭县| 开平市| 赤水市| 元氏县| 互助| 高尔夫| 玛纳斯县| 大连市| 遂川县| 通化县| 马公市| 张家界市| 伊金霍洛旗| 乌拉特中旗|