1. 程式人生 > >利用java反射機制 讀取配置檔案 實現動態類載入以及動態型別轉換

利用java反射機制 讀取配置檔案 實現動態類載入以及動態型別轉換

作者:54dabang

在spring的學習過程之中,我們可以看出通過配置檔案來動態管理bean物件的好處(鬆耦合 可以讓零散部分組成一個整體,而這些整體並不在意之間彼此的細節,從而達到了真正的物理上的疏散耦合,而非邏輯,有了IOC之後,我們可以讓SPRING充當各框架中的整合器,把技術框架進行完美的結合)。

Spring實現的一個重要的機制是通過反射(java.lang.reflect)讀取配置檔案,通過配置檔案來動態生成配置檔案中的類物件。 Java 動態載入類主要是為了不改變主程式程式碼,通過修改配置檔案就可以操作不同的物件執行不同的功能 。

由於java是強型別語言,本文根據一篇老外的部落格,給出了一種可以實現動態型別轉換的可行性方法和思路。

本文主要幫助你完成一下學習目標:

(1)反射機制最基礎的學習。

(2)    通過最基礎的java正則表示式讀取配置檔案,獲取需要的資訊。

(3)    模擬spring的IOC機制,實現類的動態載入。

(4)    給出程式原始碼,測試,總結

(5)    利用java反射機制來實現動態型別轉換(待完成)

一 java反射機制最基礎的學習

(1)關於java反射機制最基礎的學習可以參考部落格

這裡講兩種方式列出來:

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流的操作,比較簡單。為方便大家理解,我這裡將其簡化為一個字串,然後利用正則表示式從中提取資訊。

關於正則表示式的詳細學習,可以參考我的部落格:

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

<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>

在這裡 我自定義了一個配置檔案資訊,放到字串中。

其配置格式為: 屬性名稱:值,

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反射機制來實現動態型別轉換(待完成)

主要實現思想來自於老外的一篇部落格:

由於今天老師給我安排了任務,我將在未來有時間的情況下,將部落格翻譯成中文並解析。