国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

手寫(xiě)Spring之IOC基于xml動(dòng)態(tài)創(chuàng)建對(duì)象

monw3c / 2379人閱讀

Spring作為Java Web最為流行的框架之一,其功能之強(qiáng)大,封裝細(xì)節(jié)之全面不用過(guò)多贅述。使用Spring的方式很簡(jiǎn)單,不需要關(guān)注細(xì)節(jié),把對(duì)象的創(chuàng)建和對(duì)象之間的關(guān)系都交給框架來(lái)管理,僅僅做好配置文件和實(shí)現(xiàn)具體的業(yè)務(wù)邏輯即可。可以說(shuō)Spring為我們?cè)诰帉?xiě)Java Web應(yīng)用時(shí)省去了大量重復(fù)的代碼,并且可以降低對(duì)象與對(duì)象之間的耦合度。但若只是知其然,而不知其所以然,在編程時(shí)也難免會(huì)遇到各種問(wèn)題,個(gè)人的水平也難以有所長(zhǎng)進(jìn)。

因此這篇文章的目的是分享本人對(duì)于SpringIOC如何實(shí)現(xiàn)控制反轉(zhuǎn),以及如何在運(yùn)行過(guò)程中動(dòng)態(tài)創(chuàng)建對(duì)象的理解,算是在漫長(zhǎng)的學(xué)習(xí)過(guò)程中的一個(gè)小小的標(biāo)的。廢話(huà)不多說(shuō),直接上干貨!

在手寫(xiě)Spring容器之前,需要做一些前期的準(zhǔn)備工作:

首先是創(chuàng)建項(xiàng)目,在這里我為了后期下載jar包方便,創(chuàng)建的是maven工程,是在JDK1.7的環(huán)境下。當(dāng)然你也可以創(chuàng)建普通的Java工程,在需要使用第三方的jar包時(shí)手動(dòng)導(dǎo)入。

在pom.xml文件中添加jar包依賴(lài)路徑,下載所需要的第三方API,本次需要使用dom4j去解析xml配置文件。

  
      
      dom4j  
      dom4j  
      1.6.1  
      
  

創(chuàng)建xml配置文件,為了后面使用方便,在這里我起名為:user.xml,放在根目錄下:

配置文件內(nèi)容如下:

  
   
      
          
          
          
      
      
          
          
          
      

然后根據(jù)xml配置文件中的class路徑創(chuàng)建對(duì)應(yīng)的POJO實(shí)體類(lèi):User

User類(lèi)中內(nèi)容如下(為了節(jié)省篇幅,省略setter和getter方法):

public class User {  
    private Integer id;  
    private String name;  
    private String password;  
    public User() {  
        System.out.println("無(wú)參構(gòu)造方法執(zhí)行");  
    }  
    //setters和getters...  
}

主角登場(chǎng)...

創(chuàng)建ClassPathXmlApplicationContext類(lèi):

先定義幾個(gè)后面要用到的容器,這里我使用的是Map來(lái)存儲(chǔ)對(duì)象:

package applicationContext;  

public class ClassPathXmlApplicationContext {  
    /**存儲(chǔ)單例對(duì)象容器*/  
    private Map singletonBeanFactory;  
    /**存儲(chǔ)創(chuàng)建類(lèi)定義對(duì)象的容器*/  
    private Map> beanDefinationFactory;  
    /**存儲(chǔ)beanElement對(duì)象容器*/  
    private Map beanEleMap;  
    /**存儲(chǔ)bean的scope屬性容器*/  
    private Map beanScopeMap;  
}  

定義有參的構(gòu)造方法,在構(gòu)造方法中初始化容器,并調(diào)用初始化方法:

/**有參的構(gòu)造方法,在創(chuàng)建此類(lèi)實(shí)例時(shí)需要指定xml文件路徑*/  
public ClassPathXmlApplicationContext(String xmlPath) {  
    //初始化容器  
    singletonBeanFactory = new ConcurrentHashMap();  
    beanDefinationFactory = new ConcurrentHashMap>();  
    beanEleMap = new ConcurrentHashMap();  
    beanScopeMap = new ConcurrentHashMap();  
    //調(diào)用初始化方法  
    init(xmlPath);  
}  

init初始化方法內(nèi)容如下,每一行我都加了詳細(xì)的注釋?zhuān)?qǐng)直接看代碼:

/** 
 * 初始化方法,在創(chuàng)建ClassPathXmlApplicationContext對(duì)象時(shí)初始化容器, 
 * 并解析xml配置文件,獲取bean元素,在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建對(duì)象,并為對(duì)象的屬性賦值, 
 * 最后把對(duì)象存放在容器中以供獲取 
 * @param xmlPath 配置文件路徑 
 */  
private void init(String xmlPath) {  
    /* 
     * 使用dom4j技術(shù)讀取xml文檔 
     * 首先創(chuàng)建SAXReader對(duì)象 
     */  
    SAXReader reader = new SAXReader();  
    try {  
        //獲取讀取xml配置文件的輸入流  
        InputStream is = getClass().getClassLoader().getResourceAsStream(xmlPath);  
        //讀取xml,該操作會(huì)返回一個(gè)Document對(duì)象  
        Document document = reader.read(is);  
        //獲取文檔的根元素  
        Element rootElement = document.getRootElement();  
        //獲取根元素下所有的bean元素,elements方法會(huì)返回元素的集合  
        List beanElements = rootElement.elements("bean");  
        //遍歷元素集合  
        for (Element beanEle : beanElements) {  
            //獲取bean的id值,該值用于作為key存儲(chǔ)于Map集合中  
            String beanId = beanEle.attributeValue("id");  
            //將beanElement對(duì)象存入map中,為對(duì)象設(shè)置屬性值時(shí)使用  
            beanEleMap.put(beanId, beanEle);  
            //獲取bean的scope值  
            String beanScope = beanEle.attributeValue("scope");  
            //如果beanScope不等于null,將bean的scope值存入map中方便后續(xù)使用  
            if(beanScope!=null){  
                beanScopeMap.put(beanId, beanScope);  
            }  
            //獲取bean的class路徑  
            String beanClassPath = beanEle.attributeValue("class");  
            //利用反射技術(shù)根據(jù)獲得的beanClass路徑得到類(lèi)定義對(duì)象  
            Class cls = Class.forName(beanClassPath);  
            //如果反射獲取的類(lèi)定義對(duì)象不為null,則放入工廠中方便創(chuàng)建其實(shí)例對(duì)象  
            if(cls!=null){  
                beanDefinationFactory.put(beanId, cls);  
            }  
        }  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
}

以上為創(chuàng)建ClassPathXmlApplicationContext對(duì)象時(shí)自動(dòng)啟用的初始化方法,要想獲取對(duì)象則需要使用getBean方法,代碼如下:

/** 
 * 根據(jù)傳入的bean的id值獲取容器中的對(duì)象,類(lèi)型為Object 
 */  
public Object getBean(String beanId){  
    //根據(jù)傳入beanId獲取類(lèi)對(duì)象  
    Class cls = beanDefinationFactory.get(beanId);  
    //根據(jù)id獲取該bean對(duì)象的element元素對(duì)象  
    Element beanEle = beanEleMap.get(beanId);  
    //獲取存在map中的bean元素的scope屬性值  
    String scope = beanScopeMap.get(beanId);  
    Object obj = null;  
    try {  
        //如果scope等于singleton,創(chuàng)建單例對(duì)象  
        if("singleton".equals(scope) || null == scope){  
            //判斷容器中是否已有該對(duì)象的實(shí)例,如果沒(méi)有,創(chuàng)建一個(gè)實(shí)例對(duì)象放到容器中  
            if(singletonBeanFactory.get(beanId)==null){  
                Object instance = cls.newInstance();  
                singletonBeanFactory.put(beanId,instance);  
            }  
            //根據(jù)beanId獲取對(duì)象  
            obj = singletonBeanFactory.get(beanId);  
        }  
        //如果scope等于prototype,則創(chuàng)建并返回多例對(duì)象  
        if("prototype".equals(scope)){  
            obj = cls.newInstance();  
        }  
        setFieldValues(beanId, beanEle, scope, cls, obj);  
        return obj;  
    } catch (InstantiationException e) {  
        e.printStackTrace();  
    } catch (IllegalAccessException e) {  
        e.printStackTrace();  
    }  
    //暫不支持其它類(lèi)型,若不是以上兩種類(lèi)型或遭遇異常,返回null  
    return null;  
}  
/** 
 * 此為重載方法,在根據(jù)傳入的bean的id值獲取容器中的對(duì)象的同時(shí),還可以自動(dòng)轉(zhuǎn)換類(lèi)型, 
 * 返回指定的類(lèi)型,在調(diào)用該方法時(shí)省去強(qiáng)轉(zhuǎn)的步驟,傳入時(shí)第二個(gè)參數(shù)為指定的類(lèi)型, 
 * 方法實(shí)現(xiàn)同上一個(gè)方法,只是在返回對(duì)象前加了類(lèi)型強(qiáng)轉(zhuǎn) 
 */  
public T getBean(String beanId,Class c){  
    return (T)getBean(beanId);  
      
}

在以上的getBean方法中,調(diào)用了setFieldValues方法,該方法代碼如下:

/** 
 * 該方法用于為對(duì)象設(shè)置成員屬性值 
 * @param beanEle bean所對(duì)應(yīng)的element對(duì)象 
 * @param beanId bean元素的id屬性 
 * @param beanScope bean元素的scope屬性 
 * @param cls 類(lèi)對(duì)象 
 * @param obj 要為其成員屬性賦值的實(shí)例對(duì)象 
 */  
private void setFieldValues(String beanId,Element beanEle,String beanScope,Class cls,Object obj) {  
    try {  
        //獲取每個(gè)bean元素下的所有property元素,該元素用于給屬性賦值  
        List propEles = beanEle.elements("property");  
        //如果property元素集合為null,調(diào)用putInMap方法將對(duì)象放進(jìn)Map中  
        if(propEles==null){  
            return;  
        }  
        //遍歷property元素集合  
        for (Element propEle : propEles) {  
            //獲取每個(gè)元素的name屬性值和value屬性值  
            String fieldName = propEle.attributeValue("name");  
            String fieldValue = propEle.attributeValue("value");  
            //利用反射技術(shù)根據(jù)name屬性值獲得類(lèi)的成員屬性  
            Field field = cls.getDeclaredField(fieldName);  
            //將該屬性設(shè)置為可訪問(wèn)(防止成員屬性被私有化導(dǎo)致訪問(wèn)失敗)  
            field.setAccessible(true);  
            //獲取成員屬性的類(lèi)型名稱(chēng),若非字符串類(lèi)型,則需要做相應(yīng)轉(zhuǎn)換  
            String fieldTypeName = field.getType().getName();  
            //判斷該成員屬性是否為int或Integer類(lèi)型  
            if("int".equals(fieldTypeName) || "java.lang.Integer".equals(fieldTypeName)){  
                //轉(zhuǎn)換為int類(lèi)型并為該成員屬性賦值  
                int intFieldValue = Integer.parseInt(fieldValue);  
                field.set(obj, intFieldValue);  
            }  
            //判斷該成員屬性是否為String類(lèi)型  
            if("java.lang.String".equals(fieldTypeName)){  
                //為該成員屬性賦值  
                field.set(obj, fieldValue);  
            }  
            //此處省略其它類(lèi)型的判斷......道理相同!  
        }  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
}

以上是獲取單例或多例對(duì)象時(shí)需要調(diào)用的getBean方法的全部?jī)?nèi)容。當(dāng)調(diào)用者使用完容器之后,自然還需要關(guān)閉容器釋放資源,因此還需要有一個(gè)destroy方法:

/** 
 * 銷(xiāo)毀方法,用于釋放資源 
 */  
public void destroy(){  
    singletonBeanFactory.clear();  
    singletonBeanFactory = null;  
      
    beanDefinationFactory.clear();  
    beanDefinationFactory = null;  
      
    beanEleMap.clear();  
    beanEleMap = null;  
      
    beanScopeMap.clear();  
    beanScopeMap = null;  
}

至此,ClassPathXmlApplicationContext類(lèi)中的內(nèi)容全部完成,可以寫(xiě)測(cè)試類(lèi)進(jìn)行測(cè)試:

測(cè)試類(lèi)內(nèi)容如下,這里我就簡(jiǎn)單寫(xiě)main方法進(jìn)行測(cè)試:

public class springIocTest {  
    public static void main(String[] args) {  
        //創(chuàng)建ClassPathXmlApplicationContext對(duì)象  
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("user.xml");  
        //使用手動(dòng)強(qiáng)轉(zhuǎn)的方式獲取單例的User對(duì)象  
        User user1_1 = (User) ctx.getBean("user1");  
        System.out.println("單例user1_1:"+user1_1);  
        //使用傳入類(lèi)對(duì)象的方式獲取單例的User對(duì)象  
        User user1_2 = ctx.getBean("user1",User.class);  
        System.out.println("單例user1_2:"+user1_2);  
        //使用手動(dòng)強(qiáng)轉(zhuǎn)的方式獲取多例的User對(duì)象  
        User user2_1 = (User)ctx.getBean("user2");  
        System.out.println("多例user2_1:"+user2_1);  
        //使用傳入類(lèi)對(duì)象的方式獲取多例的User對(duì)象  
        User user2_2 = ctx.getBean("user2",User.class);  
        System.out.println("多例user2_2:"+user2_2);  
    }  
} 

控制臺(tái)打印輸出結(jié)果:

從控制臺(tái)輸出的結(jié)果中可以看到,獲取到了4個(gè)對(duì)象,其中前兩個(gè)為單例對(duì)象,后兩個(gè)為多例對(duì)象,兩個(gè)單例對(duì)象在默認(rèn)調(diào)用Object類(lèi)中的toString方法是其地址值的hashCode十六進(jìn)制的映射,其映射值完全一致,可以說(shuō)明是同一個(gè)對(duì)象。而且創(chuàng)建了4個(gè)對(duì)象,其無(wú)參的構(gòu)造方法只執(zhí)行了三次。

如果在User類(lèi)型加入toString方法:

@Override  
public String toString() {  
    return "User [id=" + id + ", name=" + name + ", password=" + password + "]";  
}  

再次運(yùn)行程序,控制臺(tái)輸出結(jié)果如下:

可以看到對(duì)象所定義的屬性值也在創(chuàng)建時(shí)成功賦值了。

以上是我近期學(xué)習(xí)Spring所總結(jié)的內(nèi)容,關(guān)于創(chuàng)建多例對(duì)象的源碼其實(shí)我也沒(méi)有找到,目前所寫(xiě)的只是基于我的思路寫(xiě)出來(lái)的方案,與大家一起分享。由于個(gè)人水平有限,難免會(huì)有寫(xiě)錯(cuò)或者遺漏的地方,甚至可能會(huì)有以偏概全。但這并不重要,正如開(kāi)篇所說(shuō),這只是我學(xué)習(xí)Java在編程成長(zhǎng)路上的一個(gè)小小的標(biāo)的。如果有大牛看到,歡迎留言指正,不勝感激~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/68377.html

相關(guān)文章

  • 手寫(xiě)SpringDI依賴(lài)注入

    摘要:如感興趣,可移步手寫(xiě)之基于動(dòng)態(tài)創(chuàng)建對(duì)象手寫(xiě)之基于注解動(dòng)態(tài)創(chuàng)建對(duì)象今天將詳細(xì)介紹如何手寫(xiě)依賴(lài)注入,在運(yùn)行過(guò)程中如何動(dòng)態(tài)地為對(duì)象的屬性賦值。完成后在中會(huì)有相關(guān)的包出現(xiàn)進(jìn)行注入前需要?jiǎng)?chuàng)建工廠,在運(yùn)行時(shí)從工廠中取出對(duì)象為屬性賦值。 前兩篇文章介紹了關(guān)于手寫(xiě)Spring IOC控制反轉(zhuǎn),由Spring工廠在運(yùn)行過(guò)程中動(dòng)態(tài)地創(chuàng)建對(duì)象的兩種方式。如感興趣,可移步: 手寫(xiě)Spring之IOC基于xml...

    Cruise_Chan 評(píng)論0 收藏0
  • 手寫(xiě)SpringIOC基于注解動(dòng)態(tài)創(chuàng)建對(duì)象

    摘要:上一篇博客介紹了如何基于配置文件在運(yùn)行時(shí)創(chuàng)建實(shí)例對(duì)象,這篇博客將介紹基于注解方式怎樣實(shí)現(xiàn)對(duì)象的創(chuàng)建。方便測(cè)試,該類(lèi)型分別創(chuàng)建兩個(gè)單例和多例的類(lèi)型。注意這種為對(duì)象注入屬性值的方式耦合度較高,可根據(jù)情況使用。 上一篇博客介紹了如何基于xml配置文件在運(yùn)行時(shí)創(chuàng)建實(shí)例對(duì)象,這篇博客將介紹基于注解方式怎樣實(shí)現(xiàn)對(duì)象的創(chuàng)建。 廢話(huà)不多說(shuō),直接上代碼。 首先還是創(chuàng)建項(xiàng)目,由于這次不需要使用第三方的AP...

    Andrman 評(píng)論0 收藏0
  • Spring入門(mén)IOC和AOP學(xué)習(xí)筆記

    摘要:入門(mén)和學(xué)習(xí)筆記概述框架的核心有兩個(gè)容器作為超級(jí)大工廠,負(fù)責(zé)管理創(chuàng)建所有的對(duì)象,這些對(duì)象被稱(chēng)為。中的一些術(shù)語(yǔ)切面切面組織多個(gè),放在切面中定義。 Spring入門(mén)IOC和AOP學(xué)習(xí)筆記 概述 Spring框架的核心有兩個(gè): Spring容器作為超級(jí)大工廠,負(fù)責(zé)管理、創(chuàng)建所有的Java對(duì)象,這些Java對(duì)象被稱(chēng)為Bean。 Spring容器管理容器中Bean之間的依賴(lài)關(guān)系,使用一種叫做依賴(lài)...

    wenyiweb 評(píng)論0 收藏0
  • 明天面試?嚇得我趕緊手寫(xiě)了一個(gè)Spring

    摘要:你都是如何回答面試官的問(wèn)題的我不知道,我一般會(huì)通過(guò)手寫(xiě)一個(gè)來(lái)加深自己的印象。如今,已然成為了一個(gè)生態(tài)。運(yùn)行階段主要是完成容器啟動(dòng)以后,完成用戶(hù)請(qǐng)求的內(nèi)部調(diào)度,并返回響應(yīng)結(jié)果。因此,要先寫(xiě)一個(gè)針對(duì)類(lèi)名首字母處理的工具方法。 引言 幾乎每個(gè)面試的程序員都會(huì)碰到Spring相關(guān)的面試問(wèn)題,或淺或深。你都是如何回答面試官的問(wèn)題的?——我不知道,我一般會(huì)通過(guò)手寫(xiě)一個(gè)Spring來(lái)加深自己的印象。...

    stefanieliang 評(píng)論0 收藏0
  • 仿照 Spring 實(shí)現(xiàn)簡(jiǎn)單的 IOC 和 AOP - 下篇

    摘要:在上文中,我實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關(guān)中的。初始化的工作算是結(jié)束了,此時(shí)處于就緒狀態(tài),等待外部程序的調(diào)用。其中動(dòng)態(tài)代理只能代理實(shí)現(xiàn)了接口的對(duì)象,而動(dòng)態(tài)代理則無(wú)此限制。 1. 背景 本文承接上文,來(lái)繼續(xù)說(shuō)說(shuō) IOC 和 AOP 的仿寫(xiě)。在上文中,我實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的 IOC 和 AOP 容器。上文實(shí)現(xiàn)的 IOC 和 AOP 功能很單一,且 I...

    AlexTuan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<