赛迪网 > IT技术 Java > Java大图列表
  IT资讯搜索
 
IT产品搜索
[程序开发][网管世界][网络安全][数据库技术]
[操作系统][嘉宾聊天·在线访谈][活动集锦]
[精彩专题][Symantec专区][订阅IT技术周刊]
[开发论坛][网管论坛][安全论坛][数据库论坛]
[操作系统论坛][Sybase专区][IBM dW技术专区]
[病毒求助][病毒与漏洞播报][文档·源码下载]

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

发布时间:2007.12.28 09:15     来源:赛迪网    作者:baocl

//首先定义一个接口来隔离类:
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做参数的调用。
        有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,而不仅仅供我们饭后闲聊.
    (责任编辑:包春林)


[ 发表评论 ] 字体[  ] [ 打印 ] [ 进入博客 ] [ 进入论坛 ]  [ 推荐给朋友 ]
  相关文章
· Java语言深入:如何编写安全的Java代码 (12-27) · Java语言:敏捷开发技巧-消除代码异味 (12-27)
· 进阶:Java开源项目Hibernate快速入门 (12-27) · Hibernate源码中几个包的作用简要介绍 (12-27)
· 语言深入:java中究竟是传值还是传引用 (12-27) · JAVA进阶:hibernate配置文件异常的排除 (12-27)
· 关于提高Java技能的几种简单有效的方法 (12-27) · 进阶:关于EJB返回值的最好的解决方案 (12-27)
· ServletContext与ServletConfig的分析 (12-27) · 基础:关于EJB返回值的最好的解决方案 (12-27)
  客户需求反馈表
* 姓  名:
更多资料  了解方案  认识厂商
* 单位名称:
* 联系电话:
* 电子邮件:
  赛迪推荐  
  手机·资费 ·新品·导购·评测·手机资费·宽带
手机搜索  诺基亚 N73 MOTO Z6
  IT产品 ·笔记本·台式机·服务器·打印·投影
IT产品搜索 
  IT技术 ·开发·网管·安全·数据库·操作系统
  信息化 ·热点·专题·访谈·周刊·方案案例
· 推动产业升级 沪年内首推电子商务地方法规
· 中国域名成为全球顶级域名 促进社会信息化
· 签合同前的四问 谈八大厂商“云计算”理念
· 亚略特烟草解决方案 移民安置信息管理系统
  IT博客 ·曾剑秋·项立刚·Java学习·网管
  IT技术论坛 ·开发·网管·安全·数据库·系统