利用java反射机制 读取配置文件 实现动态类加载以及动态类型转换

作者:54dabang

在spring的学习过程之中,我们可以看出通过配置文件来动态管理bean对象的好处(松耦合 可以让零散部分组成一个整体,而这些整体并不在意之间彼此的细节,从而达到了真正的物理上的疏散耦合,而非逻辑,有了IOC之后,我们可以让SPRING充当各框架中的整合器,把技术框架进行完美的结合)。

Spring实现的一个重要的机制是通过反射(java.lang.reflect)读取配置文件,通过配置文件来动态生成配置文件中的类对象。 Java 动态加载类主要是为了不改变主程序代码,通过修改配置文件就可以操作不同的对象执行不同的功能 。

由于java是强类型语言,本文根据一篇老外的博客,给出了一种可以实现动态类型转换的可行性方法和思路。

本文主要帮助你完成一下学习目标:

(1)反射机制最基础的学习。

(2)    通过最基础的java正则表达式读取配置文件,获取需要的信息。

(3)    模拟spring的IOC机制,实现类的动态加载。

(4)    给出程序源码,测试,总结

(5)    利用java反射机制来实现动态类型转换(待完成)

一 java反射机制最基础的学习

(1)关于java反射机制最基础的学习可以参考博客

http://blog.csdn.net/xiaoxian8023/article/details/9206055 ,内容比较详细。但是这篇文章里查找方法时,只能根据methodName进行查找,无法精确查找到重载的方法(根据参数查找)。

这里讲两种方式列出来:

A)只通过方法的名字进行查找 并调用 参数:被调用对象的实例 方法名 方法调用所需要的参数

public Object invokeMethodGernaral(Object owner,String methodName,Object[]args) 
    {
      //a.先获取对象所属的类
      Class ownerClass=owner.getClass();
       Method method=null;
       Object result=null;
        //b.获取需要调用的方法
       for(Method m:ownerClass.getDeclaredMethods())
       {
       	if(m.getName().equalsIgnoreCase(methodName))
       	{
       		method=m;
       		break;
       	}
       }
       try {
       //c.调用该方法
        result=method.invoke(owner, args);//调用方法
      } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
       return result;
    }

B) 只通过方法的名字和参数进行精确匹配查找 并调用 参数:被调用对象的实例 方法名 参数的类型 方法调用所需要的参数

<pre name="code" class="java">public Object invokeMethod(Object owner,String methodName,Class[]clz,Object[] args) throws Exception {  
      //a.得到对象所属类    
      Class ownerClass=owner.getClass();
      //b.根据方法名称和参数名称 获取该类的某个方法   
      Method method=ownerClass.getMethod(methodName,clz);//第二个参数是通过类型来获取 有个缺点就是参数类型必须要填写
      //c.执行某个对象的方法  
      Object result=method.invoke(owner,args); //必须要有类对象才可以调用
      //d.输出结果信息  
      System.out.println("结果返回值:"+ result);  
      return result;  
  }

 通过最基础的java正则表达式读取配置文件,获取需要的信息。

从配置文件里读取信息,主要是用到IO流的操作,比较简单。为方便大家理解,我这里将其简化为一个字符串,然后利用正则表达式从中提取信息。

关于正则表达式的详细学习,可以参考我的博客:

http://blog.csdn.net/leixingbang1989/article/details/26486927

例如要匹配一下类型的字符串:

<metahttp-equiv="Content-Type"content="text/html; charset= UTF-8 ">

其中标红的部分为想要获取的数据,注意这里要获取的数据长度不固定,并且可能为unicode

Gb2312等其他编码类型,在这里我们所希望获取的是其编码方式。

这里给出一段最简单的代码:

public static String parse (String s)
{
  Pattern pattern =Pattern.compile("charset=(.+?)\"");
  //通配符中也要加入转移字符 (.+?)代表要查找的内容
  Matcher matcher=pattern.matcher(s);
  while(matcher.find())
  {
     System.out.println(matcher.group(1));
  }
  return s;
}

三 模拟spring的IOC机制,读取配置文件,实现类的动态加载

Spring的一个配置文件格式如下:

<beans>
  <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl" >
  </bean>
  <bean id="userService" class="com.bjsxt.service.UserService" >
    <property name="userDAO" bean="u"/>
  </bean>
</beans>

我们可以用Pattern pattern =Pattern. compile ("<beans>(.+?)</beans>"); 来获取bean对象配置信息,然后再次利用正则表达式获取每个bean信息。

在这里 我自定义了一个配置文件信息,放到字符串中。

其配置格式为: 属性名称:值,

String Configure="Class:com.bjsxt.service.school,Method:getStudentInfo,args:Tom,argsType:java.lang.String";//格式固定 可以用正则表达式提取
    String []split={":",","};//格式为   name:value, 所以分隔符为 : , 
    parseData p=new parseData(Configure);//实现方式为正则表达式提取需要的字符串
    //(1) 获取类名 方法名 参数 参数类型信息  
    String className= p.getInfo("Class", split);
      String MethodName=p.getInfo("Method", split);
      String arg=p.getInfo("args", split);
      Object []args={arg};
  String argsType=p.getInfo("argsType", split);

四 给出程序源码,测试,总结

package com.bjsxt.service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class DynamicInvocation {
     public static void main(String[] a) throws Exception {
    String Configure="Class:com.bjsxt.service.school,Method:getStudentInfo,args:Tom,argsType:java.lang.String";//格式固定 可以用正则表达式提取
    String []split={":",","};//格式为	name:value, 所以分隔符为 : , 
    parseData p=new parseData(Configure);//实现方式为正则表达式提取需要的字符串
    //(1) 获取类名 方法名 参数 参数类型信息  
    String className= p.getInfo("Class", split);
     String MethodName=p.getInfo("Method", split);
     String arg=p.getInfo("args", split);
     Object []args={arg};
     String argsType=p.getInfo("argsType", split);
    //(2) 创建未知对象实例
    Object s=Class.forName(className).newInstance();// 注意我们目前创建的对象并不知道其类型
    //(3)方法调用
    //3.1仅通过方法名查找查找方法并调用 缺点:有可能有方法是重载的
    DynamicInvocation inv=new DynamicInvocation();
    inv.invokeMethodGernaral(s, MethodName, args);
    //3.2通过方法名 和参数 查找方法并调用
    Class cls=Class.forName(argsType);
    System.out.println(cls.getName());
    Class []clz={cls};
    inv.invokeMethod(s, MethodName, clz, args);
    //(4)动态强制类型转换
    Class intClass=Class.forName("java.lang.Integer");
    System.out.println(Integer.class);
    
  }
  public Object invokeMethodGernaral(Object owner,String methodName,Object[]args)//只通过方法的名字进行查找 并调用
    {
      //a.先获取对象所属的类
      Class ownerClass=owner.getClass();
       Method method=null;
       Object result=null;
        //b.获取需要调用的方法
       for(Method m:ownerClass.getDeclaredMethods())
       {
       	if(m.getName().equalsIgnoreCase(methodName))
       	{
       		method=m;
       		break;
       	}
       }
       try {
       //c.调用该方法
        result=method.invoke(owner, args);//调用方法
      } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
       return result;
    }
  public Object invokeMethod(Object owner,String methodName,Class[]clz,Object[] args) throws Exception {  
     //a.得到对象所属类	 
     Class ownerClass=owner.getClass();
     //b.根据方法名称和参数名称 获取该类的某个方法	
     Method method=ownerClass.getMethod(methodName,clz);//第二个参数是通过类型来获取 有个缺点就是参数类型必须要填写
     //c.执行某个对象的方法  
     Object result=method.invoke(owner,args); //必须要有类对象才可以调用
     //d.输出结果信息  
     System.out.println("结果返回值:"+ result);  
     return result;  
  }  
}
package com.bjsxt.service;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class parseData {
  private String strSource;//数据源
  public parseData(String s)
  {
    this.strSource=s;
  }
  public  String getInfo(String name,String []split)//名称,值,分隔符
  {
    String str=name+split[0]+"(.+?)"+split[1];
     //System.out.println(str);
      Pattern pattern =Pattern.compile(str);//匹配的模式
      Matcher matcher=pattern.matcher(this.strSource);
    String value="";
    boolean isFind=false;
    if(matcher.find())
      {
      value=matcher.group(1);
      }else//可能是最后一个字符
      {
      	pattern=Pattern.compile(name+split[0]+"(.+?)"+"$");//$ 表示为限定结尾
          matcher=pattern.matcher(this.strSource);
      	if(matcher.find())
      	{
      		value=matcher.group(1);
      	}
      		
      }
    return value;
  }

}

五 利用java反射机制来实现动态类型转换(待完成)

主要实现思想来自于老外的一篇博客:

http://prajith-javatechnical.blogspot.in/2014/09/casting-java-object-dynamically-using.html

由于今天老师给我安排了任务,我将在未来有时间的情况下,将博客翻译成中文并解析。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值