From 45609bc22b6eb26436b616a4c893edb4809ae2b0 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 27 Sep 2019 23:20:43 +0800 Subject: [PATCH] enhance aop --- .../java/cn/hutool/aop/aspects/Aspect.java | 26 +- .../cn/hutool/aop/aspects/SimpleAspect.java | 36 ++- .../aop/aspects/TimeIntervalAspect.java | 30 +- .../aop/interceptor/CglibInterceptor.java | 33 +-- .../aop/interceptor/JdkInterceptor.java | 26 +- .../cn/hutool/aop/proxy/JdkProxyFactory.java | 10 +- .../test/java/cn/hutool/aop/test/AopTest.java | 96 +++--- .../java/cn/hutool/core/util/ReflectUtil.java | 273 ++++++++++-------- 8 files changed, 280 insertions(+), 250 deletions(-) diff --git a/hutool-aop/src/main/java/cn/hutool/aop/aspects/Aspect.java b/hutool-aop/src/main/java/cn/hutool/aop/aspects/Aspect.java index 5ab798b5c..52e86cd28 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/aspects/Aspect.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/aspects/Aspect.java @@ -4,19 +4,19 @@ import java.lang.reflect.Method; /** * 切面接口 - * + * * @author looly * @author ted.L * @since 4.18 */ -public interface Aspect{ +public interface Aspect { /** * 目标方法执行前的操作 - * + * * @param target 目标对象 * @param method 目标方法 - * @param args 参数 + * @param args 参数 * @return 是否继续执行接下来的操作 */ boolean before(Object target, Method method, Object[] args); @@ -24,25 +24,25 @@ public interface Aspect{ /** * 目标方法执行后的操作 * 如果 target.method 抛出异常且 + * + * @param target 目标对象 + * @param method 目标方法 + * @param args 参数 + * @param returnVal 目标方法执行返回值 + * @return 是否允许返回值(接下来的操作) * @see Aspect#afterException 返回true,则不会执行此操作 * 如果 * @see Aspect#afterException 返回false,则无论target.method是否抛出异常,均会执行此操作 - * - * @param target 目标对象 - * @param method 目标方法 - * @param args 参数 - * @param returnVal 目标方法执行返回值 - * @return 是否允许返回值(接下来的操作) */ boolean after(Object target, Method method, Object[] args, Object returnVal); /** * 目标方法抛出异常时的操作 - * + * * @param target 目标对象 * @param method 目标方法 - * @param args 参数 - * @param e 异常 + * @param args 参数 + * @param e 异常 * @return 是否允许抛出异常 */ boolean afterException(Object target, Method method, Object[] args, Throwable e); diff --git a/hutool-aop/src/main/java/cn/hutool/aop/aspects/SimpleAspect.java b/hutool-aop/src/main/java/cn/hutool/aop/aspects/SimpleAspect.java index c118a7056..99f959da2 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/aspects/SimpleAspect.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/aspects/SimpleAspect.java @@ -6,38 +6,42 @@ import java.lang.reflect.Method; /** * 简单切面类,不做任何操作
* 可以继承此类实现自己需要的方法即可 - * - * @author Looly - * @author ted.L * + * @author Looly, ted.L */ -public abstract class SimpleAspect implements Aspect, Serializable{ +public class SimpleAspect implements Aspect, Serializable { private static final long serialVersionUID = 1L; - /** - * @see Aspect#before(Object, Method, Object[]) - * @return 是否继续执行接下来的操作 默认值true - */ @Override public boolean before(Object target, Method method, Object[] args) { //继承此类后实现此方法 return true; } - /** - * @see Aspect#after(Object, Method, Object[], Object) - * @return 是否允许返回值(接下来的操作) 默认值true - */ + + /** + * 目标方法执行后的操作 + * 如果 target.method 抛出异常且 + * + * @param target 目标对象 + * @param method 目标方法 + * @param args 参数 + * @return 是否允许返回值(接下来的操作) + * @see Aspect#afterException 返回true,则不会执行此操作 + * 如果 + * @see Aspect#afterException 返回false,则无论target.method是否抛出异常,均会执行此操作 + */ + public boolean after(Object target, Method method, Object[] args) { + //继承此类后实现此方法 + return after(target, method, args, null); + } + @Override public boolean after(Object target, Method method, Object[] args, Object returnVal) { //继承此类后实现此方法 return true; } - /** - * @see Aspect#afterException(Object, Method, Object[], Throwable) - * @return 是否允许抛出异常 默认值true - */ @Override public boolean afterException(Object target, Method method, Object[] args, Throwable e) { //继承此类后实现此方法 diff --git a/hutool-aop/src/main/java/cn/hutool/aop/aspects/TimeIntervalAspect.java b/hutool-aop/src/main/java/cn/hutool/aop/aspects/TimeIntervalAspect.java index 3c6fa66cb..854267fcb 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/aspects/TimeIntervalAspect.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/aspects/TimeIntervalAspect.java @@ -8,23 +8,27 @@ import cn.hutool.core.util.StrUtil; /** * 通过日志打印方法的执行时间的切面 - * @author Looly * + * @author Looly */ public class TimeIntervalAspect extends SimpleAspect { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private TimeInterval interval = new TimeInterval(); + private TimeInterval interval = new TimeInterval(); - @Override - public boolean before(Object target, Method method, Object[] args) { - interval.start(); - return true; - } + @Override + public boolean before(Object target, Method method, Object[] args) { + interval.start(); + return true; + } - @Override - public boolean after(Object target, Method method, Object[] args, Object returnVal) { - Console.log("Method [{}.{}] execute spend [{}]ms return value [{}]", target.getClass().getName(), method.getName(), interval.intervalMs(), StrUtil.toString(returnVal)); - return true; - } + @Override + public boolean after(Object target, Method method, Object[] args, Object returnVal) { + Console.log("Method [{}.{}] execute spend [{}]ms return value [{}]", + target.getClass().getName(), // + method.getName(), // + interval.intervalMs(), // + returnVal); + return true; + } } diff --git a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java index 8c53df4cd..d8b3ddaff 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java @@ -1,30 +1,27 @@ package cn.hutool.aop.interceptor; +import cn.hutool.aop.aspects.Aspect; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; + import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import cn.hutool.aop.aspects.Aspect; -import cn.hutool.core.exceptions.UtilException; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - /** * Cglib实现的动态代理切面 - * - * @author looly - * @author ted.L * + * @author looly, ted.L */ public class CglibInterceptor implements MethodInterceptor, Serializable { private static final long serialVersionUID = 1L; - + private Object target; private Aspect aspect; /** * 构造 - * + * * @param target 被代理对象 * @param aspect 切面实现 */ @@ -40,22 +37,20 @@ public class CglibInterceptor implements MethodInterceptor, Serializable { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { Object result = null; + + // 开始前回调 if (aspect.before(target, method, args)) { try { - // result = ReflectUtil.invoke(target, method, args); result = proxy.invokeSuper(obj, args); - } catch (UtilException e) { - final Throwable cause = e.getCause(); - if (!(e.getCause() instanceof InvocationTargetException)) { - // 其它异常属于代理的异常,直接抛出 + } catch (InvocationTargetException e) { + // 异常回调(只捕获业务代码导致的异常,而非反射导致的异常) + if (aspect.afterException(target, method, args, e.getTargetException())) { throw e; } - if(aspect.afterException(target, method, args, ((InvocationTargetException) cause).getTargetException())){ - throw e; - } - } } + + // 结束执行回调 if (aspect.after(target, method, args, result)) { return result; } diff --git a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/JdkInterceptor.java b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/JdkInterceptor.java index 73b89ba83..7250fc9d6 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/JdkInterceptor.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/JdkInterceptor.java @@ -7,16 +7,16 @@ import java.lang.reflect.Method; import cn.hutool.aop.aspects.Aspect; import cn.hutool.core.exceptions.UtilException; +import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ReflectUtil; /** * JDK实现的动态代理切面 - * + * * @author Looly * @author ted.L - * */ -public class JdkInterceptor implements InvocationHandler, Serializable{ +public class JdkInterceptor implements InvocationHandler, Serializable { private static final long serialVersionUID = 1L; private Object target; @@ -24,7 +24,7 @@ public class JdkInterceptor implements InvocationHandler, Serializable{ /** * 构造 - * + * * @param target 被代理对象 * @param aspect 切面实现 */ @@ -42,20 +42,22 @@ public class JdkInterceptor implements InvocationHandler, Serializable{ final Object target = this.target; final Aspect aspect = this.aspect; Object result = null; + + // 开始前回调 if (aspect.before(target, method, args)) { + ReflectUtil.setAccessible(method); + try { - result = ReflectUtil.invoke(target, method, args); - } catch (UtilException e) { - final Throwable cause = e.getCause(); - if (!(e.getCause() instanceof InvocationTargetException)) { - // 其它异常属于代理的异常,直接抛出 - throw e; - } - if(aspect.afterException(target, method, args, ((InvocationTargetException) cause).getTargetException())){ + result = method.invoke(ClassUtil.isStatic(method) ? null : target, args); + } catch (InvocationTargetException e) { + // 异常回调(只捕获业务代码导致的异常,而非反射导致的异常) + if (aspect.afterException(target, method, args, e.getTargetException())) { throw e; } } } + + // 结束执行回调 if (aspect.after(target, method, args, result)) { return result; } diff --git a/hutool-aop/src/main/java/cn/hutool/aop/proxy/JdkProxyFactory.java b/hutool-aop/src/main/java/cn/hutool/aop/proxy/JdkProxyFactory.java index d0b53ac4c..5b4803cf4 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/proxy/JdkProxyFactory.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/proxy/JdkProxyFactory.java @@ -6,16 +6,18 @@ import cn.hutool.aop.interceptor.JdkInterceptor; /** * JDK实现的切面代理 - * - * @author looly * + * @author looly */ -public class JdkProxyFactory extends ProxyFactory{ +public class JdkProxyFactory extends ProxyFactory { private static final long serialVersionUID = 1L; @Override @SuppressWarnings("unchecked") public T proxy(T target, Aspect aspect) { - return (T) ProxyUtil.newProxyInstance(target.getClass().getClassLoader(), new JdkInterceptor(target, aspect), target.getClass().getInterfaces()); + return (T) ProxyUtil.newProxyInstance(// + target.getClass().getClassLoader(), // + new JdkInterceptor(target, aspect), // + target.getClass().getInterfaces()); } } diff --git a/hutool-aop/src/test/java/cn/hutool/aop/test/AopTest.java b/hutool-aop/src/test/java/cn/hutool/aop/test/AopTest.java index 6ca1b9800..32d69854f 100644 --- a/hutool-aop/src/test/java/cn/hutool/aop/test/AopTest.java +++ b/hutool-aop/src/test/java/cn/hutool/aop/test/AopTest.java @@ -1,5 +1,6 @@ package cn.hutool.aop.test; +import cn.hutool.core.lang.Console; import org.junit.Assert; import org.junit.Test; @@ -8,66 +9,63 @@ import cn.hutool.aop.aspects.TimeIntervalAspect; /** * AOP模块单元测试 - * - * @author Looly * + * @author Looly */ public class AopTest { - @Test - public void aopTest() { - Animal cat = ProxyUtil.proxy(new Cat(), TimeIntervalAspect.class); - String result = cat.eat(); - Assert.assertEquals("猫吃鱼", result); - cat.seize(); - } + @Test + public void aopTest() { + Animal cat = ProxyUtil.proxy(new Cat(), TimeIntervalAspect.class); + String result = cat.eat(); + Assert.assertEquals("猫吃鱼", result); + cat.seize(); + } - @Test - public void aopByCglibTest() { - Dog dog = ProxyUtil.proxy(new Dog(), TimeIntervalAspect.class); - String result = dog.eat(); - Assert.assertEquals("狗吃肉", result); + @Test + public void aopByCglibTest() { + Dog dog = ProxyUtil.proxy(new Dog(), TimeIntervalAspect.class); + String result = dog.eat(); + Assert.assertEquals("狗吃肉", result); dog.seize(); - } + } - interface Animal { - String eat(); + interface Animal { + String eat(); - void seize(); - } + void seize(); + } - /** - * 有接口 - * - * @author looly - * - */ - static class Cat implements Animal { + /** + * 有接口 + * + * @author looly + */ + static class Cat implements Animal { - @Override - public String eat() { - return "猫吃鱼"; - } + @Override + public String eat() { + return "猫吃鱼"; + } - @Override - public void seize() { - System.out.println("抓了条鱼"); - } - } + @Override + public void seize() { + Console.log("抓了条鱼"); + } + } - /** - * 无接口 - * - * @author looly - * - */ - static class Dog { - public String eat() { - return "狗吃肉"; - } + /** + * 无接口 + * + * @author looly + */ + static class Dog { + public String eat() { + return "狗吃肉"; + } - public void seize() { - System.out.println("抓了只鸡"); - } - } + public void seize() { + Console.log("抓了只鸡"); + } + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java index 9e5f5adcf..5cc1a824f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java @@ -1,13 +1,5 @@ package cn.hutool.core.util; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.exceptions.UtilException; @@ -15,27 +7,43 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Filter; import cn.hutool.core.lang.SimpleCache; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + /** * 反射工具类 - * + * * @author Looly * @since 3.0.9 */ public class ReflectUtil { - /** 构造对象缓存 */ + /** + * 构造对象缓存 + */ private static final SimpleCache, Constructor[]> CONSTRUCTORS_CACHE = new SimpleCache<>(); - /** 字段缓存 */ + /** + * 字段缓存 + */ private static final SimpleCache, Field[]> FIELDS_CACHE = new SimpleCache<>(); - /** 方法缓存 */ + /** + * 方法缓存 + */ private static final SimpleCache, Method[]> METHODS_CACHE = new SimpleCache<>(); // --------------------------------------------------------------------------------------------------------- Constructor + /** * 查找类中的指定参数的构造方法,如果找到构造方法,会自动设置可访问为true - * - * @param 对象类型 - * @param clazz 类 + * + * @param 对象类型 + * @param clazz 类 * @param parameterTypes 参数类型,只要任何一个参数是指定参数的父类或接口或相等即可,此参数可以不传 * @return 构造方法,如果未找到返回null */ @@ -51,7 +59,7 @@ public class ReflectUtil { pts = constructor.getParameterTypes(); if (ClassUtil.isAllAssignableFrom(pts, parameterTypes)) { // 构造可访问 - constructor.setAccessible(true); + setAccessible(constructor); return (Constructor) constructor; } } @@ -60,8 +68,8 @@ public class ReflectUtil { /** * 获得一个类中所有构造列表 - * - * @param 构造的对象类型 + * + * @param 构造的对象类型 * @param beanClass 类 * @return 字段列表 * @throws SecurityException 安全检查异常 @@ -80,7 +88,7 @@ public class ReflectUtil { /** * 获得一个类中所有字段列表,直接反射获取,无缓存 - * + * * @param beanClass 类 * @return 字段列表 * @throws SecurityException 安全检查异常 @@ -91,11 +99,12 @@ public class ReflectUtil { } // --------------------------------------------------------------------------------------------------------- Field + /** * 查找指定类中是否包含指定名称对应的字段,包括所有字段(包括非public字段),也包括父类和Object类的字段 - * + * * @param beanClass 被查找字段的类,不能为null - * @param name 字段名 + * @param name 字段名 * @return 是否包含字段 * @throws SecurityException 安全异常 * @since 4.1.21 @@ -103,12 +112,12 @@ public class ReflectUtil { public static boolean hasField(Class beanClass, String name) throws SecurityException { return null != getField(beanClass, name); } - + /** * 查找指定类中的所有字段(包括非public字段),也包括父类和Object类的字段, 字段不存在则返回null - * + * * @param beanClass 被查找字段的类,不能为null - * @param name 字段名 + * @param name 字段名 * @return 字段 * @throws SecurityException 安全异常 */ @@ -126,7 +135,7 @@ public class ReflectUtil { /** * 获得一个类中所有字段列表,包括其父类中的字段 - * + * * @param beanClass 类 * @return 字段列表 * @throws SecurityException 安全检查异常 @@ -143,8 +152,8 @@ public class ReflectUtil { /** * 获得一个类中所有字段列表,直接反射获取,无缓存 - * - * @param beanClass 类 + * + * @param beanClass 类 * @param withSuperClassFieds 是否包括父类的字段列表 * @return 字段列表 * @throws SecurityException 安全检查异常 @@ -170,8 +179,8 @@ public class ReflectUtil { /** * 获取字段值 - * - * @param obj 对象 + * + * @param obj 对象 * @param fieldName 字段名 * @return 字段值 * @throws UtilException 包装IllegalAccessException异常 @@ -185,8 +194,8 @@ public class ReflectUtil { /** * 获取字段值 - * - * @param obj 对象 + * + * @param obj 对象 * @param field 字段 * @return 字段值 * @throws UtilException 包装IllegalAccessException异常 @@ -195,8 +204,8 @@ public class ReflectUtil { if (null == obj || null == field) { return null; } - field.setAccessible(true); - Object result = null; + setAccessible(field); + Object result; try { result = field.get(obj); } catch (IllegalAccessException e) { @@ -207,6 +216,7 @@ public class ReflectUtil { /** * 获取所有字段的值 + * * @param obj bean对象 * @return 字段值数组 * @since 4.1.17 @@ -227,16 +237,16 @@ public class ReflectUtil { /** * 设置字段值 - * - * @param obj 对象 + * + * @param obj 对象 * @param fieldName 字段名 - * @param value 值,值类型必须与字段类型匹配,不会自动转换对象类型 + * @param value 值,值类型必须与字段类型匹配,不会自动转换对象类型 * @throws UtilException 包装IllegalAccessException异常 */ public static void setFieldValue(Object obj, String fieldName, Object value) throws UtilException { Assert.notNull(obj); Assert.notBlank(fieldName); - + final Field field = getField(obj.getClass(), fieldName); Assert.notNull(field, "Field [{}] is not exist in [{}]", fieldName, obj.getClass().getName()); setFieldValue(obj, field, value); @@ -244,8 +254,8 @@ public class ReflectUtil { /** * 设置字段值 - * - * @param obj 对象 + * + * @param obj 对象 * @param field 字段 * @param value 值,值类型必须与字段类型匹配,不会自动转换对象类型 * @throws UtilException UtilException 包装IllegalAccessException异常 @@ -253,19 +263,20 @@ public class ReflectUtil { public static void setFieldValue(Object obj, Field field, Object value) throws UtilException { Assert.notNull(obj); Assert.notNull(field, "Field in [{}] not exist !", obj.getClass().getName()); - field.setAccessible(true); - - if(null != value) { + + setAccessible(field); + + if (null != value) { Class fieldType = field.getType(); - if(false == fieldType.isAssignableFrom(value.getClass())) { + if (false == fieldType.isAssignableFrom(value.getClass())) { //对于类型不同的字段,尝试转换,转换失败则使用原对象类型 final Object targetValue = Convert.convert(fieldType, value); - if(null != targetValue) { + if (null != targetValue) { value = targetValue; } } } - + try { field.set(obj, value); } catch (IllegalAccessException e) { @@ -274,17 +285,18 @@ public class ReflectUtil { } // --------------------------------------------------------------------------------------------------------- method + /** * 获得指定类本类及其父类中的Public方法名
* 去重重载的方法 - * + * * @param clazz 类 * @return 方法名Set */ public static Set getPublicMethodNames(Class clazz) { - final HashSet methodSet = new HashSet(); + final HashSet methodSet = new HashSet<>(); final Method[] methodArray = getPublicMethods(clazz); - if(ArrayUtil.isNotEmpty(methodArray)) { + if (ArrayUtil.isNotEmpty(methodArray)) { for (Method method : methodArray) { methodSet.add(method.getName()); } @@ -294,7 +306,7 @@ public class ReflectUtil { /** * 获得本类及其父类所有Public方法 - * + * * @param clazz 查找方法的类 * @return 过滤后的方法列表 */ @@ -304,8 +316,8 @@ public class ReflectUtil { /** * 获得指定类过滤后的Public方法列表 - * - * @param clazz 查找方法的类 + * + * @param clazz 查找方法的类 * @param filter 过滤器 * @return 过滤后的方法列表 */ @@ -331,8 +343,8 @@ public class ReflectUtil { /** * 获得指定类过滤后的Public方法列表 - * - * @param clazz 查找方法的类 + * + * @param clazz 查找方法的类 * @param excludeMethods 不包括的方法 * @return 过滤后的方法列表 */ @@ -348,8 +360,8 @@ public class ReflectUtil { /** * 获得指定类过滤后的Public方法列表 - * - * @param clazz 查找方法的类 + * + * @param clazz 查找方法的类 * @param excludeMethodNames 不包括的方法名列表 * @return 过滤后的方法列表 */ @@ -365,8 +377,8 @@ public class ReflectUtil { /** * 查找指定Public方法 如果找不到对应的方法或方法不为public的则返回null - * - * @param clazz 类 + * + * @param clazz 类 * @param methodName 方法名 * @param paramTypes 参数类型 * @return 方法 @@ -379,17 +391,17 @@ public class ReflectUtil { return null; } } - + /** * 查找指定对象中的所有方法(包括非public方法),也包括父对象和Object类的方法 - * + * *

* 此方法为精准获取方法名,即方法名和参数数量和类型必须一致,否则返回null。 *

- * - * @param obj 被查找的对象,如果为{@code null}返回{@code null} + * + * @param obj 被查找的对象,如果为{@code null}返回{@code null} * @param methodName 方法名,如果为空字符串返回{@code null} - * @param args 参数 + * @param args 参数 * @return 方法 * @throws SecurityException 无访问权限抛出异常 */ @@ -402,12 +414,12 @@ public class ReflectUtil { /** * 忽略大小写查找指定方法,如果找不到对应的方法则返回null - * + * *

* 此方法为精准获取方法名,即方法名和参数数量和类型必须一致,否则返回null。 *

- * - * @param clazz 类,如果为{@code null}返回{@code null} + * + * @param clazz 类,如果为{@code null}返回{@code null} * @param methodName 方法名,如果为空字符串返回{@code null} * @param paramTypes 参数类型,指定参数类型如果是方法的子类也算 * @return 方法 @@ -420,12 +432,12 @@ public class ReflectUtil { /** * 查找指定方法 如果找不到对应的方法则返回null - * + * *

* 此方法为精准获取方法名,即方法名和参数数量和类型必须一致,否则返回null。 *

- * - * @param clazz 类,如果为{@code null}返回{@code null} + * + * @param clazz 类,如果为{@code null}返回{@code null} * @param methodName 方法名,如果为空字符串返回{@code null} * @param paramTypes 参数类型,指定参数类型如果是方法的子类也算 * @return 方法 @@ -437,12 +449,12 @@ public class ReflectUtil { /** * 查找指定方法 如果找不到对应的方法则返回null - * + * *

* 此方法为精准获取方法名,即方法名和参数数量和类型必须一致,否则返回null。 *

- * - * @param clazz 类,如果为{@code null}返回{@code null} + * + * @param clazz 类,如果为{@code null}返回{@code null} * @param ignoreCase 是否忽略大小写 * @param methodName 方法名,如果为空字符串返回{@code null} * @param paramTypes 参数类型,指定参数类型如果是方法的子类也算 @@ -467,15 +479,15 @@ public class ReflectUtil { } return null; } - + /** * 按照方法名查找指定方法名的方法,只返回匹配到的第一个方法,如果找不到对应的方法则返回null - * + * *

* 此方法只检查方法名是否一致,并不检查参数的一致性。 *

- * - * @param clazz 类,如果为{@code null}返回{@code null} + * + * @param clazz 类,如果为{@code null}返回{@code null} * @param methodName 方法名,如果为空字符串返回{@code null} * @return 方法 * @throws SecurityException 无权访问抛出异常 @@ -484,15 +496,15 @@ public class ReflectUtil { public static Method getMethodByName(Class clazz, String methodName) throws SecurityException { return getMethodByName(clazz, false, methodName); } - + /** * 按照方法名查找指定方法名的方法,只返回匹配到的第一个方法,如果找不到对应的方法则返回null - * + * *

* 此方法只检查方法名是否一致(忽略大小写),并不检查参数的一致性。 *

- * - * @param clazz 类,如果为{@code null}返回{@code null} + * + * @param clazz 类,如果为{@code null}返回{@code null} * @param methodName 方法名,如果为空字符串返回{@code null} * @return 方法 * @throws SecurityException 无权访问抛出异常 @@ -501,15 +513,15 @@ public class ReflectUtil { public static Method getMethodByNameIgnoreCase(Class clazz, String methodName) throws SecurityException { return getMethodByName(clazz, true, methodName); } - + /** * 按照方法名查找指定方法名的方法,只返回匹配到的第一个方法,如果找不到对应的方法则返回null - * + * *

* 此方法只检查方法名是否一致,并不检查参数的一致性。 *

- * - * @param clazz 类,如果为{@code null}返回{@code null} + * + * @param clazz 类,如果为{@code null}返回{@code null} * @param ignoreCase 是否忽略大小写 * @param methodName 方法名,如果为空字符串返回{@code null} * @return 方法 @@ -535,13 +547,13 @@ public class ReflectUtil { /** * 获得指定类中的Public方法名
* 去重重载的方法 - * + * * @param clazz 类 * @return 方法名Set * @throws SecurityException 安全异常 */ public static Set getMethodNames(Class clazz) throws SecurityException { - final HashSet methodSet = new HashSet(); + final HashSet methodSet = new HashSet<>(); final Method[] methods = getMethods(clazz); for (Method method : methods) { methodSet.add(method.getName()); @@ -551,8 +563,8 @@ public class ReflectUtil { /** * 获得指定类过滤后的Public方法列表 - * - * @param clazz 查找方法的类 + * + * @param clazz 查找方法的类 * @param filter 过滤器 * @return 过滤后的方法列表 * @throws SecurityException 安全异常 @@ -566,7 +578,7 @@ public class ReflectUtil { /** * 获得一个类中所有方法列表,包括其父类中的方法 - * + * * @param beanClass 类 * @return 方法列表 * @throws SecurityException 安全检查异常 @@ -583,8 +595,8 @@ public class ReflectUtil { /** * 获得一个类中所有方法列表,直接反射获取,无缓存 - * - * @param beanClass 类 + * + * @param beanClass 类 * @param withSuperClassMethods 是否包括父类的方法列表 * @return 方法列表 * @throws SecurityException 安全检查异常 @@ -610,7 +622,7 @@ public class ReflectUtil { /** * 是否为equals方法 - * + * * @param method 方法 * @return 是否为equals方法 */ @@ -624,7 +636,7 @@ public class ReflectUtil { /** * 是否为hashCode方法 - * + * * @param method 方法 * @return 是否为hashCode方法 */ @@ -634,7 +646,7 @@ public class ReflectUtil { /** * 是否为toString方法 - * + * * @param method 方法 * @return 是否为toString方法 */ @@ -643,10 +655,11 @@ public class ReflectUtil { } // --------------------------------------------------------------------------------------------------------- newInstance + /** * 实例化对象 - * - * @param 对象类型 + * + * @param 对象类型 * @param clazz 类名 * @return 对象 * @throws UtilException 包装各类异常 @@ -662,9 +675,9 @@ public class ReflectUtil { /** * 实例化对象 - * - * @param 对象类型 - * @param clazz 类 + * + * @param 对象类型 + * @param clazz 类 * @param params 构造函数参数 * @return 对象 * @throws UtilException 包装各类异常 @@ -682,7 +695,7 @@ public class ReflectUtil { final Class[] paramTypes = ClassUtil.getClasses(params); final Constructor constructor = getConstructor(clazz, paramTypes); if (null == constructor) { - throw new UtilException("No Constructor matched for parameter types: [{}]", new Object[] { paramTypes }); + throw new UtilException("No Constructor matched for parameter types: [{}]", new Object[]{paramTypes}); } try { return constructor.newInstance(params); @@ -693,8 +706,8 @@ public class ReflectUtil { /** * 尝试遍历并调用此类的所有构造方法,直到构造成功并返回 - * - * @param 对象类型 + * + * @param 对象类型 * @param beanClass 被构造的类 * @return 构造后的对象 */ @@ -706,7 +719,7 @@ public class ReflectUtil { // ignore // 默认构造不存在的情况下查找其它构造 } - + final Constructor[] constructors = getConstructors(beanClass); Class[] parameterTypes; for (Constructor constructor : constructors) { @@ -714,24 +727,24 @@ public class ReflectUtil { if (0 == parameterTypes.length) { continue; } - constructor.setAccessible(true); + setAccessible(constructor); try { return constructor.newInstance(ClassUtil.getDefaultValues(parameterTypes)); - } catch (Exception e) { + } catch (Exception ignore) { // 构造出错时继续尝试下一种构造方式 - continue; } } return null; } // --------------------------------------------------------------------------------------------------------- invoke + /** * 执行静态方法 - * - * @param 对象类型 + * + * @param 对象类型 * @param method 方法(对象方法或static方法都可) - * @param args 参数对象 + * @param args 参数对象 * @return 结果 * @throws UtilException 多种异常包装 */ @@ -742,16 +755,16 @@ public class ReflectUtil { /** * 执行方法
* 执行前要检查给定参数: - * + * *
 	 * 1. 参数个数是否与方法参数个数一致
 	 * 2. 如果某个参数为null但是方法这个位置的参数为原始类型,则赋予原始类型默认值
 	 * 
- * - * @param 返回对象类型 - * @param obj 对象,如果执行静态方法,此值为null + * + * @param 返回对象类型 + * @param obj 对象,如果执行静态方法,此值为null * @param method 方法(对象方法或static方法都可) - * @param args 参数对象 + * @param args 参数对象 * @return 结果 * @throws UtilException 一些列异常的包装 */ @@ -774,19 +787,17 @@ public class ReflectUtil { /** * 执行方法 - * - * @param 返回对象类型 - * @param obj 对象,如果执行静态方法,此值为null + * + * @param 返回对象类型 + * @param obj 对象,如果执行静态方法,此值为null * @param method 方法(对象方法或static方法都可) - * @param args 参数对象 + * @param args 参数对象 * @return 结果 * @throws UtilException 一些列异常的包装 */ @SuppressWarnings("unchecked") public static T invoke(Object obj, Method method, Object... args) throws UtilException { - if (false == method.isAccessible()) { - method.setAccessible(true); - } + setAccessible(method); try { return (T) method.invoke(ClassUtil.isStatic(method) ? null : obj, args); @@ -797,11 +808,11 @@ public class ReflectUtil { /** * 执行对象中指定方法 - * - * @param 返回对象类型 - * @param obj 方法所在对象 + * + * @param 返回对象类型 + * @param obj 方法所在对象 * @param methodName 方法名 - * @param args 参数列表 + * @param args 参数列表 * @return 执行结果 * @throws UtilException IllegalAccessException包装 * @since 3.1.2 @@ -813,4 +824,18 @@ public class ReflectUtil { } return invoke(obj, method, args); } + + /** + * 设置方法为可访问(私有方法可以被外部调用) + * + * @param AccessibleObject的子类,比如Class、Method、Field等 + * @param accessibleObject 可设置访问权限的对象,比如Class、Method、Field等 + * @since 4.6.8 + */ + public static T setAccessible(T accessibleObject) { + if (null != accessibleObject && false == accessibleObject.isAccessible()) { + accessibleObject.setAccessible(true); + } + return accessibleObject; + } }