技术开发 频道

巧用反射实现类的动态加载

  【IT168 技术文档】首先定义一个接口来隔离类:

  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做参数的调用。

  有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,而不仅仅供我们饭后闲聊.

0
相关文章