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

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

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

    posts - 297,  comments - 1618,  trackbacks - 0
          說明:本文為孫衛(wèi)琴的《Java網(wǎng)絡編程精解》第10章的學習筆記。

    Java反射機制主要提供了如下功能:

    l         在運行時判斷任何一個對象所屬的類;

    l         在運行時構造任意一個類的對象;

    l         在運行時判斷任何一個類所具有的成員變量和方法;

    l         在運行時調(diào)用任何一個對象的方法;

    l         生成動態(tài)代理。

    一.             Java Reflection API簡介

    JDK中,主要由以下類來實現(xiàn)Java反射機制,這些類都位于java.lang.reflect包中:

    l         Class類:代表一個類;

    l         Field類:代表類的成員變量;

    l         Method類:代表類的方法;

    l         Constructor:代表類的構造方法;

    l         Array:提供了動態(tài)創(chuàng)建數(shù)組,以及訪問數(shù)組元素的靜態(tài)方法。

    至于它們的使用,請參見我先前的一篇文章:Java反射機制學習筆記(一),在此不再贅述。

    二.             在遠程方法調(diào)用中運用反射機制

    讓我們來看一個在遠程調(diào)用方法中調(diào)用運用反射機制的例子。該例的服務端SimpleServer接收客戶端SimpleClient發(fā)送的Call對象,該Call類型對象包括要調(diào)用的遠程對象的類名、方法名、參數(shù)類型和參數(shù)值信息。而服務端SimpleServer在接收到該對象時,調(diào)用指定類名的指定方法,并加組裝了返回值的Call類型對象返回給客戶端SimpleClient。若不存在所指定的類或方法,則將異常放入Call類型對象的result屬性中,返回給客戶端。下面讓我們來看看這個例子:

    1.       Call對象

    Call對象包含類名、方法名、參數(shù)類型、參數(shù)值信息和返回結果信息,是用來在客戶端和服務端進行信息交互的對象。其代碼如下:

    package remotecall;

    import java.io.Serializable;
    publicclass Call 
    implements Serializable {
        
    //類名或接口名
        private String className;

        
    //方法名
        private String methodName;

        
    //方法參數(shù)類型
        private Class[] paramTypes;

        
    //方法參數(shù)值
        private Object[] params;

        
    //返回方法的執(zhí)行結果,正常執(zhí)行時,存放返回值,發(fā)生異常時,result為該異常
        private Object result;

        
    public Call() {   
        }


        
    /**
         *構造函數(shù).
         
    */

        
    public Call(String className, String methodName,
               Class[] paramTypes, Object[] params) 
    {
           
    this.className = className;
           
    this.methodName = methodName;
           
    this.paramTypes = paramTypes;
           
    this.params = params;
        }


        
    //省略className、methodName、paramTypes、params和result的set/get方法
        public String toString() {
           
    return"className=" + className + ",methodName=" + methodName;
        }

    }

     2.       服務端SimpleServer

    服務端建立一個ServerSocket,一直讀取客戶端發(fā)送來的消息,并傳入?yún)?shù)到指定的方法,調(diào)用該方法,并將返回結果設置到Call類型對象的result屬性中,若出現(xiàn)異常情況時,將異常放入result屬性中,并將改變后的Call類型對象返回。其代碼如下所示:

    package remotecall;

    import java.io.InputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.OutputStream;
    import java.lang.reflect.Method;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.HashMap;
    import java.util.Map;

    /**
     *服務端.
     
    */

    publicclass SimpleServer 
    {
        
    //存放遠程對象的緩存
        private Map<String, Object> remoteObjects = new HashMap<String, Object>();
        
        
    /**
         *將一個遠程對象加入緩存中.
         *@paramclassNamemap中的key——類名
         *@paramremoteObject遠程對象
         
    */

        publicvoid register(String className, Object remoteObject) 
    {
           remoteObjects.put(className, remoteObject);
        }

        
        publicvoid service() 
    throws Exception {
           ServerSocket serverSocket 
    = new ServerSocket(8000);
           System.out.println(
    "服務器啟動");
           
    while(true{
               Socket socket 
    = serverSocket.accept();
               InputStream in 
    = socket.getInputStream();
               ObjectInputStream ois 
    = new ObjectInputStream(in);
               OutputStream out 
    = socket.getOutputStream();
               ObjectOutputStream oos 
    = new ObjectOutputStream(out);

               
    //接收從客戶端發(fā)送的Call對象
               Call call = (Call) ois.readObject();
               
    //調(diào)用call的toString()方法打出className和methodName
               System.out.println(call);
               
    //調(diào)用對象的相關方法
               call = invoke(call);
               
    //將放置了result值的對象放入輸出中返回
               oos.writeObject(call);

               
    //關閉相關資源
               ois.close();
               oos.close();
               socket.close();
           }

        }


        
    /**
         *調(diào)用遠程方法的指定方法,并將返回值放入call對象的result中.
         *@paramcall調(diào)用對象
         *@return返回設置了result值的call對象
         
    */

        
    public Call invoke(Call call) {
           Object result 
    = null;
           
    try {
               
    //取出對象中的各參數(shù)
               String className = call.getClassName();
               String methodName 
    = call.getMethodName();
               Class[] paramTypes 
    = call.getParamTypes();
               Object[] params 
    = call.getParams();
               
               
    //獲取類
               Class classType = Class.forName(className);
               
    //獲取方法
               Method method = classType.getMethod(methodName, paramTypes);
               
    //將className作為key在map中取出遠程對象
               Object remoteObject = remoteObjects.get(className);
               
    if (remoteObject == null{
                  thrownew Exception(className 
    + "遠程對象不存在!");
               }
     else {
                  
    //通過傳入相應參數(shù)調(diào)用remoteObject的指定方法
                  
    //并將返回值放入result中.
                  result = method.invoke(remoteObject, params);
               }

           }
     catch(Exception e) {
               result 
    = e;
           }


           
    //設置返回值
           call.setResult(result);
           
    return call;
        }


        
    /**
         *測試方法.
         
    */

        publicstaticvoid main(String[] args) 
    throws Exception {
           SimpleServer server 
    = new SimpleServer();
           
    //存放對象到remoteObjects這個map中
           server.register("remotecall.HelloService"new HelloServiceImpl());
           server.service();
        }

    }

     3.    客戶端SimpleClient

    客戶端發(fā)送組裝好的Call對象給服務端,并讀取指定方法的返回結果。其完整代碼如下:

    package remotecall;

    import java.io.InputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.OutputStream;
    import java.net.Socket;

    /**
     *客戶端類.
     
    */

    publicclass SimpleClient 
    {
        publicvoid invoke(Call call) 
    throws Exception {
           Socket socket 
    = new Socket("localhost"8000);
           OutputStream out 
    = socket.getOutputStream();
           ObjectOutputStream oos 
    = new ObjectOutputStream(out);
           InputStream in 
    = socket.getInputStream();
           ObjectInputStream ois 
    = new ObjectInputStream(in);  

           
    //向服務器發(fā)送call對象
           oos.writeObject(call);
           
    //接收從服務端發(fā)送回的對象
           call = (Call) ois.readObject();
           
    //打印結果信息
           System.out.println(call.getResult());

           
    //關閉資源
           ois.close();
           oos.close();
           socket.close();
        }

       
        
    /**
         *測試方法.
         
    */

        publicstaticvoid main(String[] args) 
    throws Exception {
           SimpleClient client 
    = new SimpleClient();

           
    //構建一個正確Call對象
           Call call = new Call();
           call.setClassName(
    "remotecall.HelloService");
           call.setMethodName(
    "echo");
           call.setParamTypes(
    new Class[]{String.class});
           call.setParams(
    new Object[]{"Hello,阿蜜果"});
           client.invoke(call);
           
           
    //構建一個錯誤的Call對象(不存在所指定的類)
           call.setClassName("remotecall.HelloEcho");
           client.invoke(call);
        }

    }

    4.    遠程類HelloService及其實現(xiàn)類HelloServiceImpl

    為了測試上面的功能,還需要模擬一個遠程對象所屬的類,本例的HelloService接口具有兩個方法,echo()getTime()。兩者的內(nèi)容如下:

    HelloService的內(nèi)容:

    package remotecall;

    import java.util.Date;

    publicinterface HelloService 
    {
        
    public String echo(String msg);

        
    public Date getTime();
    }

    HelloServiceImpl的內(nèi)容:

    package remotecall;

    import java.util.Date;

    publicclass HelloServiceImpl 
    implements HelloService {
        
    public String echo(String msg) {
           
    return"echo: " + msg;
        }


        
    public Date getTime() {
           returnnew Date();
        }

    }

        在測試時,我們首先運行服務端SimpleServer,將服務端啟動起來,接著將客戶端SimpleClient啟動,可在控制臺看到如下信息:

    客戶端的信息如下:

    echo Hello,阿蜜果

    java.lang.ClassNotFoundException: remotecall.HelloEcho

    服務端的信息如下:

    服務器啟動...

    className=remotecall.HelloServicemethodName=echo

    className=remotecall.HelloEchomethodName=echo

    三.代理模式

    代理模式是常用的Java設計模式,它的特征是代理類和委托類有相同的接口。代理類主要負責為委托類預處理消息、過濾信息、把消息轉發(fā)給委托類,以及事后處理信息等。代理類和委托類之間通常會存在關聯(lián)關系,一個代理類的對象與一個委托類的對象關聯(lián),代理類的對象并不真正實現(xiàn)服務,而是通過調(diào)用委托類的對象的相關方法,來提供特定的服務。

    根據(jù)代理類的創(chuàng)建時期,可將其分為兩類:

    l         靜態(tài)代理類:由程序員創(chuàng)建或由特定工具自動生成源代碼;

    l         動態(tài)代理類:在程序運行時,運用反射機制創(chuàng)建而成。

    1.    靜態(tài)代理類

    請參考代理模式的一些實現(xiàn)實例,在此不再詳述。

    2.    動態(tài)代理類

    動態(tài)代理類不僅簡化了編程工作,而且提高了軟件系統(tǒng)的擴展性,因為Java反射機制可以生成任意類型的動態(tài)代理類。java.lang.reflect類和InvocationHandler接口提供了生成動態(tài)代理類的能力。與之相關的方法是:getProxyClass()newProxyInstance()方法。下面讓我們來看一個動態(tài)代理類的簡單例子:

    package proxy;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    /**
     *動態(tài)代理類.
     
    */

    publicclass HelloServiceProxyFactory 
    {
        publicstatic HelloService getHelloServiceProxy(
    final HelloService helloService) {
           InvocationHandler handler 
    = new InvocationHandler() {
               
    public Object invoke(Object proxy, Method method, Object args[])
                      
    throws Exception {
                  System.out.println(
    "before calling " + method);
                  Object result 
    = method.invoke(helloService, args);
                  System.out.println(
    "after calling " + method);
                  
    return result;
               }

           }
    ;
           
           Class classType 
    = HelloService.class;
           
    return (HelloService) Proxy.newProxyInstance(classType.getClassLoader(),
                  
    new Class[]{classType},
                  handler);
        }


        
    /**
         *測試方法.
         
    */

        publicstaticvoid main(String[] args) 
    {
           HelloService helloService 
    = new HelloServiceImpl();
           HelloService helloServiceProxy 
    = HelloServiceProxyFactory.getHelloServiceProxy(
                  helloService);
           System.out.println(
    "代理類名字:" + helloServiceProxy.getClass().getName());
           System.out.println(helloService.echo(
    "Hello,阿蜜果"));
        }

    }


         運行后可看到這個代理類是動態(tài)生成的。在SpringAOP中也運到了動態(tài)代理機制,有興趣的朋友可查找相關資料。

    posted on 2007-09-19 13:21 阿蜜果 閱讀(2753) 評論(3)  編輯  收藏 所屬分類: Java


    FeedBack:
    # re: Java反射機制學習筆記(二)
    2007-09-19 14:46 | 千里冰封
    呵呵,不錯,JAVA這方面確實挺強大的,可以在運行時得到有關類的一些信息
      回復  更多評論
      
    # re: Java反射機制學習筆記(二)
    2007-09-19 19:41 |
    文章寫的不錯,人長得很好看
    頂一下  回復  更多評論
      
    # re: Java反射機制學習筆記(二)
    2007-10-12 18:29 | 大媽
    文章寫的不錯,人長得很好看 ……——……  回復  更多評論
      
    <2007年9月>
    2627282930311
    2345678
    9101112131415
    16171819202122
    23242526272829
    30123456

          生活將我們磨圓,是為了讓我們滾得更遠——“圓”來如此。
          我的作品:
          玩轉Axure RP  (2015年12月出版)
          

          Power Designer系統(tǒng)分析與建模實戰(zhàn)  (2015年7月出版)
          
         Struts2+Hibernate3+Spring2   (2010年5月出版)
         

    留言簿(263)

    隨筆分類

    隨筆檔案

    文章分類

    相冊

    關注blog

    積分與排名

    • 積分 - 2294895
    • 排名 - 3

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产成人免费片在线视频观看| 中文字幕久精品免费视频| www.免费在线观看| 亚洲午夜在线电影| 99re免费在线视频| 少妇中文字幕乱码亚洲影视 | 国产亚洲精久久久久久无码77777| 亚洲高清一区二区三区电影| 成人片黄网站A毛片免费| 日韩亚洲人成在线| 日韩视频在线精品视频免费观看| 亚洲短视频在线观看| 中文字幕在线免费观看| 91亚洲性爱在线视频| 亚洲免费福利视频| 亚洲午夜成激人情在线影院| 中文字幕无码免费久久99| 亚洲国产最大av| 噜噜嘿在线视频免费观看| 亚洲AV日韩AV一区二区三曲| 国产成人无码免费视频97| 日本一区二区在线免费观看| 亚洲精品国产V片在线观看| 中文字幕手机在线免费看电影 | 亚洲国产小视频精品久久久三级| 成人国产网站v片免费观看| 在线亚洲97se亚洲综合在线| 国产一区二区免费视频| 亚洲综合激情视频| 精品久久久久久久免费人妻| 一区二区免费在线观看| 国产亚洲精品资源在线26u| 久久精品无码专区免费东京热| 亚洲国产一区在线观看| 免费乱码中文字幕网站| 国产午夜免费高清久久影院| 亚洲午夜一区二区电影院| 免费看国产精品麻豆| a级毛片在线免费观看| 亚洲人成在线精品| 亚洲中文字幕伊人久久无码|