<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 63  文章 - 0  trackbacks - 0
    <2009年4月>
    2930311234
    567891011
    12131415161718
    19202122232425
    262728293012
    3456789

    常用鏈接

    留言簿(2)

    隨筆分類

    隨筆檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    spring IOC 機制模擬實現(xiàn)收藏  

     

           Java中,其反射和動態(tài)代理機制極其強大,我們可以通過其反射機制在運行時獲取信息。而代理是一種基本的設(shè)計模式,它是一種為了提供額外的或不同的操作而插入到真實對象中的某個對象。而Java的動態(tài)代理在代理上更進一步,既能動態(tài)的創(chuàng)建代理對象,又能動態(tài)的調(diào)用代理方法。Java的反射和動態(tài)代理機制,使Java變得更加強大。

           Spring框架這幾年風(fēng)頭正勁,雖然使用者眾多,但真正了解其內(nèi)部實現(xiàn)原理的朋友卻并不是很多。其實,了解它的內(nèi)部實現(xiàn)機制和設(shè)計思想是很有必要的大家都知道,Spring框架的IOCAOP部分功能強大,很值得我們學(xué)習(xí)。那么讓我們在這兩篇文章中分別詳細的學(xué)習(xí)IOCAOP的實現(xiàn)吧。

    在本文中,主要講述的是用Java的反射機制實現(xiàn)IOC。下面,讓我們開始IOC之旅吧!

    一.             Java反射機制概述與初探

    Java的反射機制是Java語言的一個重要特性,Java具有的比較突出的動態(tài)機制就是反射(reflection)。通過它,我們可以獲取如下信息:

    1) 在運行時判斷任意一個對象所屬的類;

    2) 在運行時獲取類的對象;

    3) 在運行時獲得類所具有的成員變量和方法等。

    下面讓我們通過調(diào)用一個Java Reflection API的演示實例來見識一下反射機制的強大。

    首先在IDE中建立名為reflection_proxyJava工程,并建立存放源文件的目錄src,并在src目錄下分別建立org.amigo. reflection目錄和org.amigo.proxy目錄來分別存放代理和反射的實例。我們在reflection目錄下建立ReflectionTest.java文件,在該文件中編寫代碼來演示Java Reflection API的使用。該類的代碼如下所示:

    package org.amigo.reflection;

    import java.awt.Button;
    import java.lang.reflect.Method;
    import java.util.Hashtable;

    /**
     *初探Java的反射機制.   
     *
    @author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     *Creationdate:2007-10-2-上午10:13:48
     
    */

    publicclass ReflectionTest 
    {

        
    /**
         *@paramargs
         
    */

        publicstaticvoid main(String[] args) 
    throws Exception {
            ReflectionTest reflection 
    = new ReflectionTest();
            reflection.getNameTest();
            System.out.println(
    "");
            reflection.getMethodTest();
        }


        
    /**
         *Class的getName()方法測試.
         *@throwsException
         
    */

        publicvoid getNameTest() 
    throws Exception {
            System.out.println(
    "===========begin getNameTest============");
            String name 
    = "阿蜜果";
            Class cls 
    = name.getClass();
            System.out.println(
    "String類名: " + cls.getName());
            Button btn 
    = new Button();
            Class btnClass 
    = btn.getClass();
            System.out.println(
    "Button類名: " + btnClass.getName());
            Class superBtnClass 
    = btnClass.getSuperclass();
            System.out.println(
    "Button的父類名: " + superBtnClass.getName());
            Class clsTest 
    = Class.forName("java.awt.Button");
            System.out.println(
    "clsTest name: " + clsTest.getName());
            System.out.println(
    "===========end getNameTest============");
        }

        
        
    /**
         *Class的getMethod()方法測試.
         *@throwsException
         
    */

        publicvoid getMethodTest() 
    throws Exception {
            System.out.println(
    "===========begin getMethodTest==========");
            Class cls 
    = Class.forName("org.amigo.reflection.ReflectionTest");
            Class ptypes[] 
    = new Class[2];
            ptypes[
    0= Class.forName("java.lang.String");
            ptypes[
    1= Class.forName("java.util.Hashtable");
            Method method 
    = cls.getMethod("testMethod", ptypes);
            Object args[] 
    = new Object[2];
            args[
    0= "hello, my dear!";
            Hashtable
    <String, String> ht = new Hashtable<String, String>();
            ht.put(
    "name""阿蜜果");
            args[
    1= ht;

            String returnStr 
    = (String) method.invoke(new ReflectionTest(), args);
            System.out.println(
    "returnStr= " + returnStr);
            System.out.println(
    "===========end getMethodTest==========");
        }


        
    public String testMethod(String str, Hashtable ht) throws Exception {
            String returnStr 
    = "返回值";
            System.out.println(
    "測試testMethod()方法調(diào)用");
            System.out.println(
    "str= " + str);
            System.out.println(
    "名字= " + (String) ht.get("name"));
            System.out.println(
    "結(jié)束testMethod()方法調(diào)用");
            
    return returnStr;
    }

    }

         運行該例,可在控制臺看到如下內(nèi)容:

    ===========begin getNameTest============

    String類名: java.lang.String

    Button類名: java.awt.Button

    Button的父類名: java.awt.Component

    clsTest name: java.awt.Button

    ===========end getNameTest============

    ===========begin getMethodTest==========

    測試testMethod()方法調(diào)用

    str= hello, my dear!

    名字= 阿蜜果

    結(jié)束testMethod()方法調(diào)用

    returnStr= 返回值

    ===========end getMethodTest==========

        分析運行結(jié)果,我們可以發(fā)現(xiàn),Java的反射機制使得我們在運行時能夠判斷一個對象所屬的類,獲取對象的方法并得其進行調(diào)用,并獲取方法的返回結(jié)果等功能。

    二.             IOC使用的背景

    在我們?nèi)粘5脑O(shè)計中,類與類之間存在著千絲萬縷的關(guān)系,如果兩個類存在著強耦合關(guān)系,那么在維護時,一個類的修改很可能會牽動另一個類的關(guān)聯(lián)修改,從而使得我們的維護工作步履維艱。下面讓我們來看這樣的一個強耦合反面例子。

    首先我們建立一個Chinese.java類,該類的sayHelloWorld(String name)方法,用中文對名為name的人問好,其內(nèi)容如下:

    package org.amigo.reflection;

    /**
     *中國人類.   
     *
    @author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     *Creationdate:2007-10-2-上午10:37:17
     
    */

    publicclass Chinese 
    {

        
    /**
         *用中文對某人問好.
         *@paramname姓名
         
    */

        publicvoid sayHelloWorld(String name) 
    {
           String helloWorld 
    = "你好," + name;
           System.out.println(helloWorld);
        }

    }

     

    下面我們接著建立一個American.java類,該類的sayHelloWorld(String name)方法,用英文對名為name的人問好,其內(nèi)容如下:

    package org.amigo.reflection;

    /**
     *美國人類.   
     *
    @author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     *@version1.0
     *Creationdate:2007-10-2-上午10:41:27

     
    */

    publicclass American 
    {

        
    /**
         *用英文對某人問好.
         *@paramname姓名
         
    */

        publicvoid sayHelloWorld(String name) 
    {
           String helloWorld 
    = "Hello," + name;
           System.out.println(helloWorld);
        }

    }

     

        最后我們編寫一個測試類對這兩個類的sayHelloWorld(String name)方法進行測試,下面是該類的內(nèi)容:

    package org.amigo.reflection;

    /**
     *HelloWorld測試.
     *
    @author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     *Creationdate:2007-10-2-上午10:45:13
     
    */

    publicclass HelloWorldTest 
    {

        
    /**
         *測試Chinese和American的sayHelloWorld()方法.
         *@paramargs
         *
    @author<a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
         *Creationdate:2007-10-2-上午10:43:51
         
    */

        publicstaticvoid main(String[] args) 
    {
           Chinese chinese 
    = new Chinese();
           chinese.sayHelloWorld(
    "阿蜜果");
           
           American american 
    = new American();
           american.sayHelloWorld(
    "Amigo");
        }

    }


        觀察HelloWorldTest我們可以很清楚的看到,該類與Chinese.java類和American.java類都存在強耦合關(guān)系。

    上面的例子讓我們想到的是在N年以前,當(dāng)我們需要某個東西時,我們一般是自己制造。但是當(dāng)發(fā)展到了一定的階段后,工廠出現(xiàn)了,我們可以工廠中購買我們需要的東西,這極大的方便了我們。在上例中,我們都是通過new來創(chuàng)建新的對象,在開發(fā)中,這種強耦合關(guān)系是我們所不提倡的,那么我們應(yīng)該如何來實現(xiàn)這個例子的解耦呢?我們接著想到了使用工廠模式,我們需要新建一個工廠類來完成對象的創(chuàng)建,并采用依賴接口的方式,此時需要對代碼進行如下修改:

    首先建立接口類Human.java,其內(nèi)容如下:

    package org.amigo.reflection;

    /**
     * 人類接口類.    
     * 
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     * Creation date: 2007-10-2 - 上午11:04:56
     
    */

    public interface Human {

        
    /**
         * 對某人問好.
         * 
    @param name 姓名
         
    */

        
    public void sayHelloWorld(String name);
    }


    并將American.java類和Chinese.java類改為實現(xiàn)該接口,即類頭分別改成:public class American implements Humanpublic class Chinese implements Human

    接著編寫HumanFactory.java工廠類,其內(nèi)容為

    package org.amigo.reflection;

    /**
     * 工廠類.    
     * 
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     * Creation date: 2007-10-2 - 上午11:09:30
     
    */

    public class HumanFactory {

           
    /**
            * 通過類型字段獲取人的相應(yīng)實例
            * 
    @param type 類型
            * 
    @return 返回相應(yīng)實例
            
    */

           
    public Human getHuman(String type) {
                  
    if ("chinese".equals(type)) {
                         
    return new Chinese();
                  }
     else {
                         
    return new American();
                  }

           }

    }


    最后我們還需要修改測試類HelloWorld.java類,修改后的內(nèi)容如下:

    package org.amigo.reflection;

    /**
     * HelloWorld測試.
     * 
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     * Creation date: 2007-10-2 - 上午10:45:13
     
    */

    public class HelloWorldTest {

           
    /**
            * 測試sayHelloWorld()方法.
            * 
    @param args
            * 
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
            * Creation date: 2007-10-2 - 上午10:43:51
            
    */

           
    public static void main(String[] args) {
                  HumanFactory factory 
    = new HumanFactory();
                  Human human1 
    = factory.getHuman("chinese");
                  human1.sayHelloWorld(
    "阿蜜果");

                  Human human2 
    = factory.getHuman("american");
                  human2.sayHelloWorld(
    "Amigo");
                  }

    }

    觀察此例我們可以看到,該類不再與具體的實現(xiàn)類ChineseAmerican存在耦合關(guān)系,而只是與它們的接口類Human存在耦合關(guān)系,具體對象的獲取只是通過傳入字符串來獲取,很大程度上降低了類與類之間的耦合性。

    但是我們還是不太滿足,因為還需要通過chineseamerican在類中獲取實例,那么當(dāng)我們需要修改時實現(xiàn)時,我們還需要在類中修改這些字符串,那么還有沒有更好的辦法呢?讓我們在下節(jié)中進行繼續(xù)探討。

    三.             IOC粉墨登場

    IOCInverse of Control)可翻譯為“控制反轉(zhuǎn)”,但大多數(shù)人都習(xí)慣將它稱為“依賴注入”。在Spring中,通過IOC可以將實現(xiàn)類、參數(shù)信息等配置在其對應(yīng)的配置文件中,那么當(dāng)需要更改實現(xiàn)類或參數(shù)信息時,只需要修改配置文件即可,這種方法在上例的基礎(chǔ)上更進一步的降低了類與類之間的耦合。我們還可以對某對象所需要的其它對象進行注入,這種注入都是在配置文件中做的,SpringIOC的實現(xiàn)原理利用的就是Java的反射機制, Spring還充當(dāng)了工廠的角色,我們不需要自己建立工廠類。Spring的工廠類會幫我們完成配置文件的讀取、利用反射機制注入對象等工作,我們可以通過bean的名稱獲取對應(yīng)的對象。

    下面讓我們看看如下的模擬Springbean工廠類:

    package org.amigo.reflection;

    import java.io.InputStream;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import org.dom4j.Attribute;
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;

    /**
     * bean工廠類.    
     * 
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     * Creation date: 2007-10-6 - 上午10:04:41
     
    */

    public class BeanFactory {
           
    private Map<String, Object> beanMap = new HashMap<String, Object>();

           
    /**
            * bean工廠的初始化.
            * 
    @param xml xml配置文件
            
    */

           
    public void init(String xml) {
                  
    try {
                         
    //讀取指定的配置文件
                         SAXReader reader = new SAXReader();
                         ClassLoader classLoader 
    = Thread.currentThread().getContextClassLoader();
                         
    //從class目錄下獲取指定的xml文件
                         InputStream ins = classLoader.getResourceAsStream(xml);
                         Document doc 
    = reader.read(ins);
                         Element root 
    = doc.getRootElement();   
                         Element foo;
                         
    //遍歷bean
                         for (Iterator i = root.elementIterator("bean"); i.hasNext();) {   
                                foo 
    = (Element) i.next();
                                
    //獲取bean的屬性id和class
                                Attribute id = foo.attribute("id");   
                                Attribute cls 
    = foo.attribute("class");
                                
    //利用Java反射機制,通過class的名稱獲取Class對象
                                Class bean = Class.forName(cls.getText());
                                
    //獲取對應(yīng)class的信息
                                java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);
                                
    //獲取其屬性描述
    java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
                                
    //設(shè)置值的方法
                                Method mSet = null;
                                
    //創(chuàng)建一個對象
                                Object obj = bean.newInstance();
                                
    //遍歷該bean的property屬性
                                for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {   
                                       Element foo2 
    = (Element) ite.next();
                                       
    //獲取該property的name屬性
                                       Attribute name = foo2.attribute("name");
                                      String value 
    = null;
                                       
    //獲取該property的子元素value的值
                                       for(Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {
                                              Element node 
    = (Element) ite1.next();                                          value = node.getText();
    break;
                                       }

                                       
    for (int k = 0; k < pd.length; k++{
                                              
    if (pd[k].getName().equalsIgnoreCase(name.getText())) {                                             mSet = pd[k].getWriteMethod();
    //利用Java的反射極致調(diào)用對象的某個set方法,并將值設(shè)置進去                                              mSet.invoke(obj, value);
    }

    }

    }


    //將對象放入beanMap中,其中key為id值,value為對象
    beanMap.put(id.getText(), obj);
    }

    }
     catch (Exception e) {
        System.out.println(e.toString());
    }

    }


           
    /**
            * 通過bean的id獲取bean的對象.
            * 
    @param beanName bean的id
            * 
    @return 返回對應(yīng)對象
            
    */

           
    public Object getBean(String beanName) {
                  Object obj 
    = beanMap.get(beanName);
                  
    return obj;
           }


           
    /**
            * 測試方法.
            * 
    @param args
            * 
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
            * Creation date: 2007-10-6 - 上午11:21:14
            
    */

           
    public static void main(String[] args) {
                 BeanFactory factory 
    = new BeanFactory();
                  factory.init(
    "config.xml");
                  JavaBean javaBean 
    = (JavaBean) factory.getBean("javaBean");
                  System.out.println(
    "userName=" + javaBean.getUserName());
                  System.out.println(
    "password=" + javaBean.getPassword());
           }

    }

    該類的init(xml)方法,通過指定的xml來給對象注入屬性,為了對該類進行測試,我還需要新建一個JavaBean和在src目錄下新建一個名為config.xml的配置文件。JavaBean的內(nèi)容如下:

    package org.amigo.reflection;

    /**
     * 
     * 簡單的bean,用于測試   
     * 
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
     * Creation date: 2007-10-6 - 上午11:24:30
     
    */

    public class JavaBean {
           
    private String userName;
           
    private String password;

        
    public String getPassword() {
                  
    return password;
           }


           
    public String getUserName() {
                  
    return userName;
           }


           
    public void setUserName(String userName) {
                  
    this.userName = userName;
           }


           
    public void setPassword(String password) {
                  
    this.password = password;
           }

    }

     

    這個簡單bean對象中有兩個屬性,分別為userNamepassword,下面我們在配置文件config.xml中對其屬性注入對應(yīng)的屬性值。配置文件內(nèi)容如下:

    <?xml version="1.0" encoding="UTF-8"?>

    <beans>
        
    <bean id="javaBean" class="org.amigo.reflection.JavaBean">
           
    <property name="userName">
               
    <value>阿蜜果</value>
           
    </property>
           
    <property name="password">
               
    <value>12345678</value>
           
    </property>
        
    </bean>
    </beans>

    類與配置文件都完成后,可以運行BeanFactory.java文件,控制臺顯示內(nèi)容為:

    userName=阿蜜果

    password=12345678

    可以看到,雖然在main()方法中沒有對屬性賦值,但屬性值已經(jīng)被注入,在BeanFactory類中的Class bean = Class.forName(cls.getText());通過類名來獲取對應(yīng)的類,mSet.invoke(obj, value);通過invoke方法來調(diào)用特定對象的特定方法,實現(xiàn)的原理都是基于Java的反射機制,在此我們有一次見證了Java反射機制的強大。

    當(dāng)然,這只是對IOC的一個簡單演示,在Spring中,情況要復(fù)雜得多,例如,可以一個bean引用另一個bean,還可以有多個配置文件、通過多種方式載入配置文件等等。不過原理還是采用Java的反射機制來實現(xiàn)IOC的。

    四.             總結(jié)

    在本文中,筆者通過講述Java反射機制概述與初探、IOC使用的背景、IOC粉墨登場等內(nèi)容,演示了Java反射機制API的強大功能,并通過編寫自己的簡單的IOC框架,讓讀者更好的理解了IOC的實現(xiàn)原理。

    本文通過IOC的一個簡要實現(xiàn)實例,模擬了SpringIOC的實現(xiàn),雖然只是完成了Spring中依賴注入的一小部分工作,但是很好的展現(xiàn)了Java反射機制在Spring中的應(yīng)用,能使我們能更好的從原理上了解IOC的實現(xiàn),也能為我們實現(xiàn)自己的準(zhǔn)Spring框架提供方案,有興趣的朋友可以通過Spring的源碼進行IOC的進一步的學(xué)習(xí)。

    posted on 2009-04-06 11:43 lanxin1020 閱讀(471) 評論(0)  編輯  收藏 所屬分類: spring
    主站蜘蛛池模板: 日韩在线视频播放免费视频完整版| 国产免费人成视频尤勿视频| 2022国内精品免费福利视频| 亚州免费一级毛片| 四虎国产精品免费视| 亚洲AV永久青草无码精品| 亚洲av无码专区在线电影天堂| 国产一二三四区乱码免费 | baoyu777永久免费视频| 三年片在线观看免费大全| 精品国产亚洲一区二区在线观看| 亚洲精品成人久久| 一级毛片在线播放免费| 18勿入网站免费永久| 亚洲色成人网站WWW永久| 亚洲一本一道一区二区三区| 黄色网址在线免费| 国产精品免费播放| 亚洲精品国产啊女成拍色拍| 亚欧乱色国产精品免费视频| 欧洲精品成人免费视频在线观看| 国产亚洲精品a在线观看app| 蜜臀亚洲AV无码精品国产午夜.| 99re免费在线视频| 国产精品亚洲mnbav网站 | 国产成人人综合亚洲欧美丁香花| 99re这里有免费视频精品| 亚洲人午夜射精精品日韩| 在线观看亚洲AV日韩AV| 久久久高清日本道免费观看| 久久久久久久亚洲精品| 亚洲暴爽av人人爽日日碰| 亚洲一区二区三区免费视频| 国产亚洲综合网曝门系列| 国产成人亚洲毛片| 无码国产精品一区二区免费I6| 亚洲AV无码久久精品色欲| xvideos永久免费入口| 国产一区二区三区无码免费| 亚洲一本之道高清乱码| 99久久人妻精品免费一区|