利用反射實現Java類的動態加載

jopen 11年前發布 | 19K 次閱讀 Java Java開發


//首先定義一個接口來隔離類:
public interface Operator
{
//    public java.util.List act(java.util.List params);
      public java.util.List act(String content,String content2,java.util.List params);
}


根據設計模式的原理,我們可以為不同的功能編寫不同的類,每個類都繼承Operator接口,客戶端只需要針對Operator接口編程就可以避免很多麻煩。比如這個類:

import java.util.*;
public class Success implements Operator
{
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("Success3");
        Operator op = new Success();
        System.out.println("act===" + op.act("Success1", "Success2", list));
    }
//       public java.util.List act(java.util.List params)
    public java.util.List act(String content, String content2,
                              java.util.List params) {
        List result = new ArrayList();
        result.add(content);
        result.add(content2);
        result.add(params);
        return result;
    }
}

同樣,也可以寫另一個類:

import java.util.*;
public class Load implements Operator
{
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("Load3");
        Operator op = new Load();
        System.out.println("act===" + op.act("Load1", "Load2", list));
    }
//       public java.util.List act(java.util.List params)
    public java.util.List act(String content, String content2,
                              java.util.List params)
    {
        List result = new ArrayList();
        result.add(content);
        result.add(content2);
        result.add(params);
        return result;
    }
}

我們還可以寫其他很多類,但是有個問題,接口是無法實例化的,我們必須手動控制具體實例化哪個類,這很不爽,如果能夠向應用程序傳遞一個參數,讓自己去選擇實例化一個類,執行它的act方法,那我們的工作就輕松多了。
 
很幸運,我使用的是Java,只有Java才提供這樣的反射機制,或者說內省機制,可以實現我們的無理要求。編寫一個配置文件emp.properties: 
#成功響應

1000=Success

#向客戶發送普通文本消息

2000=Load

#客戶向服務器發送普通文本消息

3000=Store

文件中的鍵名是客戶將發給我的消息頭,客戶發送1000給我,那么我就執行Success類的act方法,類似的如果發送2000給我,那就執行Load類的act方法,這樣一來系統就完全符合開閉原則了,如果要添加新的功能,完全不需要修改已有代碼,只需要在配置文件中添加對應規則,然后編寫新的類,實現act方法就ok,即使我棄這個項目而去,它將來也可以很好的擴展。這樣的系統具備了非常良好的擴展性和可插入性。 
下面這個例子體現了動態加載的功能,程序在執行過程中才知道應該實例化哪個類: 

import java.lang.reflect.*;
import java.util.Properties;
import java.io.FileInputStream;
import java.util.List;
//這個程序是針對Operator編程的,所以無需做任何修改,直接提供Load和Store類,就可以支持2000、3000做參數的調用
//有了這樣的內省機制,可以把接口的作用發揮到極至,設計模式也更能體現出威力,而不僅僅供我們飯后閑聊。
public class TestReflect
{
       //加載配置文件,查詢消息頭對應的類名
    private String loadProtocal(String header)
    {
        String result=null;
       try
       {
           Properties prop=new Properties();
//           FileInputStream fis=new FileInputStream("emp.properties");
//           id = prop.getProperty(idString);
//           prop.load(fis);
//           fis.close();
           prop.load(getTCL().getResourceAsStream("emp.properties"));
           result=prop.getProperty(header);
        }catch(Exception e)
       {
           System.out.println(e);
       }
        return result;
    }
 private static ClassLoader getTCL() throws IllegalAccessException,
                                            InvocationTargetException {
     Method method = null;
     try {
         method = Thread.class.getMethod("getContextClassLoader", null);
     } catch (NoSuchMethodException e) {
         return null;
     }
     return (ClassLoader)method.invoke(Thread.currentThread(), null);
 }

    //針對消息作出響應,利用反射導入對應的類
    public String response(String header,String content,String content2,List list)
    {
        String result=null;
        String s=null;
       try
       {
           /*
            * 導入屬性文件emp.properties,查詢header所對應的類的名字
            * 通過反射機制動態加載匹配的類,所有的類都被Operator接口隔離
            * 可以通過修改屬性文件、添加新的類(繼承MsgOperator接口)來擴展協議
            */
           s="org.bromon.reflect."+this.loadProtocal(header).trim();
           //加載類
           System.out.println("s==="+s);//打印 s===org.bromon.reflect.Success
           Class c=Class.forName(s);
//java.lang.reflect.Methods 是用來描述某個類中單個方法的一個類
//           Method m[] = c.getDeclaredMethods();//
//           for (int i = 0; i < m.length; i++)//
//               System.out.println(m[i].toString());
//  打印   public java.util.List org.bromon.reflect.Success.act(java.util.List)
           //創建類的事例
           Operator mo=(Operator)c.newInstance();
           System.out.println("mo==="+mo);
           //構造參數列表
           Class params[]=new Class[3];
//           params[0]=Class.forName("java.util.List");
             params[0]=Class.forName("java.lang.String");
             params[1]=Class.forName("java.lang.String");
             params[2]=Class.forName("java.util.List");
           System.out.println("params[0]==="+params[0]);
//           //查詢act方法
           Method m=c.getMethod("act",params);
           System.out.println("method=="+m.toString());
           Object[] args=new Object[3];
           args[0]=content;
           args[1]=content2;
           args[2]=list;
//           //調用方法并且獲得返回
           Object returnObject=m.invoke(mo,args);//這個地方出問題了,拋異常~~~~
//           System.out.println("returnObject==="+returnObject);
           List result2 = (List)returnObject;
           result = (String)result2.get(0);
           System.out.println("result2=="+result2);
//
        }catch(Exception e)
       {
           System.out.println("Handler-response:"+e);//Handler-response:java.lang.IllegalArgumentException: argument type mismatch
           //IllegalArgumentException - 如果該方法是實例方法,且指定對象參數不是聲明基礎方法的類或接口(或其中的子類或實現程序)的實例;
           //如果實參和形參的數量不相同;如果基本參數的解包轉換失敗;或者如果在解包后,無法通過方法調用轉換將參數值轉換為相應的形參類型。
       }
        return result;
    }
    public static void main(String args[])
    {
        TestReflect tr=new TestReflect();
          List list = new java.util.ArrayList();
          list.add("測試List");
          tr.response("2000","Load1","Load2",list);//1000是Success,2000是Load
   tr.response("1000","Success1","Success2",list);//1000是Success,2000是Load

    }
}

測試一下,run一下TestReflect類,打印內容有,great!!
result2==[Load1, Load2, [測試List]]
result2==[Success1, Success2, [測試List]]

       這個程序是針對Operator編程的,所以無需做任何修改,直接提供Load和Store類,就可以支持2000、3000做參數的調用。
        有了這樣的內省機制,可以把接口的作用發揮到極至,設計模式也更能體現出威力,而不僅僅供我們飯后閑聊.

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!