利用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 blocke.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反射機制來實現動態型別轉換(待完成)
主要實現思想來自於老外的一篇部落格:
由於今天老師給我安排了任務,我將在未來有時間的情況下,將部落格翻譯成中文並解析。