<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
          說明:本文為孫衛琴的《Java網絡編程精解》第10章的學習筆記。

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

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

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

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

    l         在運行時調用任何一個對象的方法;

    l         生成動態代理。

    一.             Java Reflection API簡介

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

    l         Class類:代表一個類;

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

    l         Method類:代表類的方法;

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

    l         Array:提供了動態創建數組,以及訪問數組元素的靜態方法。

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

    二.             在遠程方法調用中運用反射機制

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

    1.       Call對象

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

    package remotecall;

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

        
    //方法名
        private String methodName;

        
    //方法參數類型
        private Class[] paramTypes;

        
    //方法參數值
        private Object[] params;

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

        
    public Call() {   
        }


        
    /**
         *構造函數.
         
    */

        
    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,一直讀取客戶端發送來的消息,并傳入參數到指定的方法,調用該方法,并將返回結果設置到Call類型對象的result屬性中,若出現異常情況時,將異常放入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);

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

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

        }


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

        
    public Call invoke(Call call) {
           Object result 
    = null;
           
    try {
               
    //取出對象中的各參數
               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 {
                  
    //通過傳入相應參數調用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

    客戶端發送組裝好的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);  

           
    //向服務器發送call對象
           oos.writeObject(call);
           
    //接收從服務端發送回的對象
           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及其實現類HelloServiceImpl

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

    HelloService的內容:

    package remotecall;

    import java.util.Date;

    publicinterface HelloService 
    {
        
    public String echo(String msg);

        
    public Date getTime();
    }

    HelloServiceImpl的內容:

    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設計模式,它的特征是代理類和委托類有相同的接口。代理類主要負責為委托類預處理消息、過濾信息、把消息轉發給委托類,以及事后處理信息等。代理類和委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的對象并不真正實現服務,而是通過調用委托類的對象的相關方法,來提供特定的服務。

    根據代理類的創建時期,可將其分為兩類:

    l         靜態代理類:由程序員創建或由特定工具自動生成源代碼;

    l         動態代理類:在程序運行時,運用反射機制創建而成。

    1.    靜態代理類

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

    2.    動態代理類

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

    package proxy;

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

    /**
     *動態代理類.
     
    */

    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,阿蜜果"));
        }

    }


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

    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系統分析與建模實戰  (2015年7月出版)
          
         Struts2+Hibernate3+Spring2   (2010年5月出版)
         

    留言簿(263)

    隨筆分類

    隨筆檔案

    文章分類

    相冊

    關注blog

    積分與排名

    • 積分 - 2294312
    • 排名 - 3

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲AⅤ男人的天堂在线观看| 四虎精品亚洲一区二区三区| 国产男女爽爽爽免费视频| 亚洲熟妇无码一区二区三区导航| 亚洲av无码专区在线播放| 亚洲精品动漫人成3d在线| 日本黄色免费观看| 可以免费看黄视频的网站| 久久综合给合久久国产免费| 和老外3p爽粗大免费视频| 曰批全过程免费视频观看免费软件| 亚洲五月丁香综合视频| 久久亚洲精精品中文字幕| 亚洲精品乱码久久久久久久久久久久 | 特级aa**毛片免费观看| 亚洲欧美日韩久久精品| 在线观看91精品国产不卡免费| 国产h视频在线观看网站免费| 日韩免费无码视频一区二区三区| 一本到卡二卡三卡免费高 | 成人免费a级毛片| 成人免费午夜无码视频| 亚洲一区免费在线观看| 亚洲综合免费视频| 色老头永久免费网站| 成人免费福利视频| 免费观看美女用震蛋喷水的视频| 国产成人一区二区三区视频免费| 在线观看免费无码视频| 精品一区二区三区高清免费观看 | 亚洲午夜精品一级在线播放放| 免费a级毛片网站| 亚洲成AV人在线观看网址| 91福利视频免费观看| 先锋影音资源片午夜在线观看视频免费播放| 日批视频网址免费观看| 两个人日本WWW免费版| 97无码人妻福利免费公开在线视频 | AA免费观看的1000部电影| 韩国免费一级成人毛片| 免费av欧美国产在钱|