日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

java reflectionutils_Spring中的各种Utils(五):ReflectionUtils详解(转载)

發布時間:2024/7/23 javascript 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java reflectionutils_Spring中的各种Utils(五):ReflectionUtils详解(转载) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文出處:https://blog.csdn.net/wolfcode_cn/article/details/80660515

原創文章,轉載請注明出處。

本節中,我們來看看Spring針對反射提供的工具類:ReflectionUtils。反射在容器中使用是非常頻繁的了,ReflectionUtils中也提供了想當多的有用的方法,一起來看看。

在ReflectionUtils中提供了一些專門用于處理在反射中異常相關的方法,這些方法一般在Spring框架內部使用,當然,出于規范考慮,我們在開發中涉及到反射的異常,也可以使用這些方法。我們按照這些方法的調用鏈來看代碼:

void handleReflectionException(Exception ex)

處理反射中的異常,我們直接看代碼:

public static void handleReflectionException(Exception ex) {

if (ex instanceof NoSuchMethodException) {

throw new IllegalStateException("Method not found: " + ex.getMessage());

}

if (ex instanceof IllegalAccessException) {

throw new IllegalStateException("Could not access method: " + ex.getMessage());

}

if (ex instanceof InvocationTargetException) {

handleInvocationTargetException((InvocationTargetException) ex);

}

if (ex instanceof RuntimeException) {

throw (RuntimeException) ex;

}

throw new UndeclaredThrowableException(ex);

}

可以看到,代碼把NoSuchMethodException,IllegalAccessException,InvocationTargetException等反射中的檢查異常(Exception)直接包裝為對應的運行時異常(RuntimeException);這里我們可以先看一下反射中的異常:

可以看到,反射中的異常,都繼承了ReflectiveOperationException(反射操作異常),而該異常繼承了Exception;旗下再是ClassNotFoundException等具體的反射操作異常;

在方法中,如果遇到的是InvocationTargetException異常,交給handleInvocationTargetException方法處理:

public static void rethrowRuntimeException(Throwable ex) {

if (ex instanceof RuntimeException) {

throw (RuntimeException) ex;

}

if (ex instanceof Error) {

throw (Error) ex;

}

throw new UndeclaredThrowableException(ex);

}

可以看到,該方法只是判斷了運行時異常和Error;并原樣拋出;怎么理解這個方法的調用?原因很簡單,InvocationTargetException是在method.invoke的時候拋出的,方法在執行的過程中,方法本身的執行可能拋出RuntimeException或者Error,其余方法本身拋出的Exception異常直接包裝為UndeclaredThrowableException(RuntimeException)處理;

統一下來,可以這樣理解,除了在反射執行過程中遇到的Error,其余所有的Exception,都被統一轉成了RuntimeException;

接下來進入正常方法

Field findField(Class> clazz, String name, Class> type)

根據類型,字段名稱和字段類型查詢一個字段;該方法會遍歷的向父類查詢字段,查詢到的是所有字段;我們可以簡單看一下實現:

public static Field findField(Class> clazz, String name, Class> type) {

Class> searchType = clazz;

while (Object.class != searchType && searchType != null) {

Field[] fields = getDeclaredFields(searchType);

for (Field field : fields) {

if ((name == null || name.equals(field.getName())) &&

(type == null || type.equals(field.getType()))) {

return field;

}

}

searchType = searchType.getSuperclass();

}

return null;

}

代碼實現比較簡單,向上查詢字段,直到Object類型;注意,其中調用了一句代碼:

Field[] fields = getDeclaredFields(searchType);

我們來看看該代碼實現:

private static Field[] getDeclaredFields(Class> clazz) {

Field[] result = declaredFieldsCache.get(clazz);

if (result == null) {

result = clazz.getDeclaredFields();

declaredFieldsCache.put(clazz, (result.length == 0 ? NO_FIELDS : result));

}

return result;

}

可以看到,實際上,在該工具類中,對類型和字段做了緩存,保存到了declaredFieldsCache中,來看看這個cache的聲明:

private static final Map, Field[]> declaredFieldsCache =

new ConcurrentReferenceHashMap, Field[]>(256);

因為是工具類,被聲明為ConcurrentReferenceHashMap也是能夠理解;

這種緩存機制也存在于方法的查詢;

該方法還有一個簡單的版本:

Field findField(Class> clazz, String name)

void setField(Field field, Object target, Object value)

在指定對象(target)中給指定字段(field)設置指定值(value);

Object getField(Field field, Object target)

在指定對象(target)上得到指定字段(field)的值;

以上兩個方法的實現都非常簡單,分別調用了field.set和field.get方法;并處理了對應的異常;選一個實現看看:

public static void setField(Field field, Object target, Object value) {

try {

field.set(target, value);

}

catch (IllegalAccessException ex) {

handleReflectionException(ex);

throw new IllegalStateException(

"Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());

}

}

使用了handleReflectionException方法來統一處理異常;

Method findMethod(Class> clazz, String name, Class>… paramTypes)

在類型clazz上,查詢name方法,參數類型列表為paramTypes;

public static Method findMethod(Class> clazz, String name, Class>... paramTypes) {

Class> searchType = clazz;

while (searchType != null) {

Method[] methods = (searchType.isInterface() ? searchType.getMethods() : getDeclaredMethods(searchType));

for (Method method : methods) {

if (name.equals(method.getName()) &&

(paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {

return method;

}

}

searchType = searchType.getSuperclass();

}

return null;

}

可以看到,該仍然可以向上遞歸查詢方法,并且查詢到的是所有方法。

該方法也有一個簡單的版本:

Method findMethod(Class> clazz, String name)

Object invokeMethod(Method method, Object target, Object… args)

在指定對象(target)上,使用指定參數(args),執行方法(method);

該方法的實現也非常簡單:

public static Object invokeMethod(Method method, Object target, Object... args) {

try {

return method.invoke(target, args);

}

catch (Exception ex) {

handleReflectionException(ex);

}

throw new IllegalStateException("Should never get here");

}

可以看到,就只是調用了method.invoke方法,并統一處理了調用異常;

該方法也有一個簡單版本:

Object invokeMethod(Method method, Object target)

boolean declaresException(Method method, Class> exceptionType)

判斷一個方法上是否聲明了指定類型的異常;

boolean isPublicStaticFinal(Field field)

判斷字段是否是public static final的;

boolean isEqualsMethod(Method method)

判斷方法是否是equals方法;

boolean isHashCodeMethod(Method method)

判斷方法是否是hashcode方法;

boolean isToStringMethod(Method method)

判斷方法是否是toString方法;

可能有童鞋記得,在AopUtils中也有這幾個isXXX方法,是的,其實AopUtils中的isXXX方法就是調用的ReflectionUtils的這幾個方法的;

boolean isObjectMethod(Method method)

判斷方法是否是Object類上的方法;

void makeAccessible(Field field)

將一個字段設置為可讀寫,主要針對private字段;

void makeAccessible(Method method)

將一個方法設置為可調用,主要針對private方法;

void makeAccessible(Constructor> ctor)

將一個構造器設置為可調用,主要針對private構造器;

void doWithLocalMethods(Class> clazz, MethodCallback mc)

針對指定類型上的所有方法,依次調用MethodCallback回調;

首先來看看MethodCallback接口聲明:

public interface MethodCallback {

/**

* 使用指定方法完成一些操作.

*/

void doWith(Method method) throws IllegalArgumentException, IllegalAccessException;

}

其實就是一個正常的回調接口;來看看doWithLocalMethods實現:

public static void doWithLocalMethods(Class> clazz, MethodCallback mc) {

Method[] methods = getDeclaredMethods(clazz);

for (Method method : methods) {

try {

mc.doWith(method);

}catch (IllegalAccessException ex) {

throw new IllegalStateException("...");

}

}

}

其實實現很簡單,就是得到類上的所有方法,然后執行回調接口;這個方法在Spring針對bean的方法上的標簽處理時大量使用,比如@Init,@Resource,@Autowire等標簽的預處理;

該方法有一個增強版:

void doWithMethods(Class> clazz, MethodCallback mc, MethodFilter mf)

該版本提供了一個方法匹配(過濾器)MethodFilter;

我們來看看MethodFilter的接口聲明:

public interface MethodFilter {

/**

* 檢查一個指定的方法是否匹配規則

*/

boolean matches(Method method);

}

該接口就聲明了一個匹配方法,用于匹配規則;

再返回來看看doWithMethods方法的實現:

public static void doWithMethods(Class> clazz, MethodCallback mc, MethodFilter mf) {

// Keep backing up the inheritance hierarchy.

Method[] methods = getDeclaredMethods(clazz);

for (Method method : methods) {

if (mf != null && !mf.matches(method)) {

continue;

}

try {

mc.doWith(method);

}catch (IllegalAccessException ex) {

throw new IllegalStateException("...");

}

}

if (clazz.getSuperclass() != null) {

doWithMethods(clazz.getSuperclass(), mc, mf);

}else if (clazz.isInterface()) {

for (Class> superIfc : clazz.getInterfaces()) {

doWithMethods(superIfc, mc, mf);

}

}

}

該方法實現就很明確了,首先得到類上所有方法,針對每一個方法,調用MethodFilter實現匹配檢查,如果匹配上,調用MethodCallback回調方法。該方法會遞歸向上查詢所有父類和實現的接口上的所有方法并處理;

void doWithLocalFields(Class> clazz, FieldCallback fc)

那很明顯,該方法就是針對所有的字段,執行的對應的回調了,這里的FieldCallback就類似于前面的MethodCallback:

public interface FieldCallback {

/**

* 給指定的字段執行操作;

*/

void doWith(Field field) throws IllegalArgumentException, IllegalAccessException;

}

該方法的實現就類似于doWithLocalMethods的實現了:

public static void doWithLocalFields(Class> clazz, FieldCallback fc) {

for (Field field : getDeclaredFields(clazz)) {

try {

fc.doWith(field);

}catch (IllegalAccessException ex) {

throw new IllegalStateException("...");

}

}

}

得到類上所有的字段,并執行回調;同理,該方法在Spring中主要用于預處理字段上的@Autowire或者@Resource標簽;

void doWithFields(Class> clazz, FieldCallback fc, FieldFilter ff)

和doWithMethods的加強版相同,針對字段,也提供了一個擁有字段匹配(過濾)的功能方法;我們就只簡單看下FieldFilter實現即可:

public interface FieldFilter {

/**

* 檢查給定字段是否匹配;

*/

boolean matches(Field field);

}

小結

總的來說,ReflectionUtils提供的功能還算完整,其實想要實現這樣的一個工具類,也不是什么難事,更多的建議大家多看看Spring的實現,還是有不少收獲。當然,這里我們看的是Spring4.X的代碼,相信在Spring5中完全使用Java8的代碼,會更優雅。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的java reflectionutils_Spring中的各种Utils(五):ReflectionUtils详解(转载)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。