Java 反射采用 ASM 并增加缓存,高并发下大幅度性能提升

This commit is contained in:
thinkgem
2023-02-13 13:46:49 +08:00
parent fda9e9b571
commit ee50473830
8 changed files with 1889 additions and 149 deletions

View File

@@ -0,0 +1,577 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.test;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.TimeUtils;
import com.jeesite.common.reflect.ReflectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
/**
* 反射工具类 性能测试
* @author ThinkGem
* @version 2023-2-6
*/
@SuppressWarnings("rawtypes")
public class ReflectUtilsTest {
public static void main(String[] args) {
int num = 100000;
for (int i = 0; i < 5; i++) {
getMethodTest(num, Type.FIELD);
getMethodTest(num, Type.ASM);
getMethodTest(num, Type.CACHE);
getMethodTest(num, Type.NOT_CACHE);
setMethodTest(num, Type.FIELD);
setMethodTest(num, Type.ASM);
setMethodTest(num, Type.CACHE);
setMethodTest(num, Type.NOT_CACHE);
}
ReflectUtils.invokeGetter(Test.class, "staticMethodTest");
ReflectUtils.invokeSetter(Test.class, "staticMethodTest", "123");
}
public static void getMethodTest(int num, Type type) {
long start = System.currentTimeMillis();
for (int i = 0; i < num; i++) {
Test test = new Test("1", "2", "3", 4, 5, 6, new Date());
for (int j = 1; j <= 7; j++) {
String name = (j >= 1 && j <= 3 ? "str" : j >=4 && j<= 6 ? "int" : "date") + j;
Object v = null;
switch (type) {
case ASM:
v = ReflectUtils.invokeGetter(test, name);
break;
case CACHE:
v = ReflectUtils2.invokeGetterCache(test, name);
break;
case NOT_CACHE:
v = ReflectUtils2.invokeGetter(test, name);
break;
case FIELD:
v = ReflectUtils.getFieldValue(test, name);
break;
}
if (v == null) {
throw new RuntimeException("error.");
}else if (j == 1 && !v.equals(test.getStr1())) {
throw new RuntimeException("error.");
} else if (j == 4 && !v.equals(test.getInt4())) {
throw new RuntimeException("error.");
} else if (j == 7 && !v.equals(test.getDate7())) {
throw new RuntimeException("error.");
}
}
}
long total = System.currentTimeMillis() - start;
System.out.println("Get " + type.getVal() + ": " + TimeUtils.formatTime(total));
}
public static void setMethodTest(int num, Type type) {
long start = System.currentTimeMillis();
for (int i = 0; i < num; i++) {
Test test = new Test();
for (int j = 1; j <= 7; j++) {
String name = (j >= 1 && j <= 3 ? "str" : j >=4 && j<= 6 ? "int" : "date") + j;
Object v = (j >= 1 && j <= 3 ? ("str" + j) : j >=4 && j<= 6 ? (123 + j) : new Date());
switch (type) {
case ASM:
// MethodAccess ma = MethodAccess.get(test.getClass());
// ma.invoke(test, SETTER_PREFIX+StringUtils.capitalize(name), v);
ReflectUtils.invokeSetter(test, name, v);
break;
case CACHE:
ReflectUtils2.invokeSetterCache(test, name, v);
break;
case NOT_CACHE:
ReflectUtils2.invokeSetter(test, name, v);
break;
case FIELD:
ReflectUtils.setFieldValue(test, name, v);
break;
}
if (j == 1 && !v.equals(test.getStr1())) {
throw new RuntimeException("error.");
} else if (j == 4 && !v.equals(test.getInt4())) {
throw new RuntimeException("error.");
} else if (j == 7 && !v.equals(test.getDate7())) {
throw new RuntimeException("error.");
}
}
}
long total = System.currentTimeMillis() - start;
System.out.println("Set " + type.getVal() + ": " + TimeUtils.formatTime(total));
}
enum Type {
FIELD("field"),
ASM("method asm"),
CACHE("method use cache"),
NOT_CACHE("method not use cache");
private String val;
Type(String val) {
this.val = val;
}
public String getVal() {
return val;
}
}
public static class Test {
private String str1;
private String str2;
private String str3;
private Integer int4;
private Integer int5;
private Integer int6;
private Date date7;
public Test() {
}
public Test(String str1, String str2, String str3, Integer int4, Integer int5, Integer int6, Date date7) {
this.str1 = str1;
this.str2 = str2;
this.str3 = str3;
this.int4 = int4;
this.int5 = int5;
this.int6 = int6;
this.date7 = date7;
}
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
public String getStr2() {
return str2;
}
public void setStr2(String str2) {
this.str2 = str2;
}
public String getStr3() {
return str3;
}
public void setStr3(String str3) {
this.str3 = str3;
}
public Integer getInt4() {
return int4;
}
public void setInt4(Integer int4) {
this.int4 = int4;
}
public Integer getInt5() {
return int5;
}
public void setInt5(Integer int5) {
this.int5 = int5;
}
public Integer getInt6() {
return int6;
}
public void setInt6(Integer int6) {
this.int6 = int6;
}
public Date getDate7() {
return date7;
}
public void setDate7(Date date7) {
this.date7 = date7;
}
public static void getStaticMethodTest() {
System.out.println("This is a static get method");
}
public static void setStaticMethodTest(String val) {
System.out.println("This is a static set method, set val: " + val);
}
}
}
/**
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
* @author calvin、ThinkGem
* @version 2015-11-12
*/
class ReflectUtils2 {
private static Logger logger = LoggerFactory.getLogger(ReflectUtils2.class);
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static Class baseEntityClass = null;
/**
* 调用Getter方法
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")){
if (obj instanceof Map){
object = ((Map)obj).get(name);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, methodName, new Class[] {}, new Object[] {});
}
}
return (E)object;
}
/**
* 调用Getter方法
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetterCache(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")){
if (obj instanceof Map){
object = ((Map)obj).get(name);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = ReflectUtils.invokeMethodByName(object, methodName);
}
}
return (E)object;
}
/**
* 调用Setter方法仅匹配方法名
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> void invokeSetter(Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
if(i<names.length-1){
if (obj instanceof Map){
object = ((Map)obj).get(names[i]);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
Object childObj = ReflectUtils.invokeMethodByName(object, methodName);
// 如果 get 获取对象为空,并且返回值类型继承自 BaseEntity则 new 对象,并通过 set 赋予它
if (childObj == null && object != null){
Method method = getAccessibleMethod(object, methodName, new Class[] {});
if (method != null) {
Class<?> returnType = method.getReturnType();
try {
if (baseEntityClass == null) {
baseEntityClass = Class.forName("com.jeesite.common.entity.BaseEntity");
}
if (baseEntityClass.isAssignableFrom(returnType)) {
childObj = returnType.getDeclaredConstructor().newInstance();
methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, methodName, new Object[] { childObj });
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
object = childObj;
}
}else{
if (obj instanceof Map){
((Map)obj).put(names[i], value);
}else{
String methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, methodName, new Object[] { value });
}
}
}
}
/**
* 调用Setter方法仅匹配方法名
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> void invokeSetterCache(Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
if(i<names.length-1){
if (obj instanceof Map){
object = ((Map)obj).get(names[i]);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
Object childObj = ReflectUtils.invokeMethodByName(object, methodName);
// 如果 get 获取对象为空,并且返回值类型继承自 BaseEntity则 new 对象,并通过 set 赋予它
if (childObj == null && object != null){
Method method = getAccessibleMethod(object, methodName, new Class[] {});
if (method != null) {
Class<?> returnType = method.getReturnType();
try {
if (baseEntityClass == null) {
baseEntityClass = Class.forName("com.jeesite.common.entity.BaseEntity");
}
if (baseEntityClass.isAssignableFrom(returnType)) {
childObj = returnType.getDeclaredConstructor().newInstance();
methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
ReflectUtils.invokeMethodByName(object, methodName, childObj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
object = childObj;
}
}else{
if (obj instanceof Map){
((Map)obj).put(names[i], value);
}else{
String methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
ReflectUtils.invokeMethodByName(object, methodName, value);
}
}
}
}
/**
* 直接读取对象属性值无视private/protected修饰符不经过getter函数
*/
@SuppressWarnings("unchecked")
public static <E> E getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
if (obj != null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
}
return null;
}
E result = null;
try {
result = (E)field.get(obj);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常: {}", e.getMessage());
}
return result;
}
/**
* 直接设置对象属性值无视private/protected修饰符不经过setter函数
*/
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return;
}
try {
field.set(obj, value);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常: {}", e.getMessage());
}
}
/**
* 直接调用对象方法无视private/protected修饰符
* 用于一次性调用的情况否则应使用getAccessibleMethod()函数获得Method后反复调用
* 同时匹配方法名+参数类型,
* 支持静态类及方法调用
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
if (obj == null || methodName == null){
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
if (obj != null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
}
return null;
}
try {
return (E)method.invoke(obj.getClass() == Class.class ? null : obj, args);
} catch (Exception e) {
String msg = "method: "+method+", obj: "+obj+", args: "+args+"";
throw ReflectUtils.convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 直接调用对象方法无视private/protected修饰符
* 用于一次性调用的情况否则应使用getAccessibleMethodByName()函数获得Method后反复调用
* 只匹配函数名,如果有多个同名函数调用第一个,
* 支持静态类及方法调用
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null) {
// 如果为空不报错,直接返回空。
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
if (obj != null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
}
return null;
}
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class<?>[] cs = method.getParameterTypes();
for (int i=0; i<cs.length; i++){
if (args[i] != null && !args[i].getClass().equals(cs[i])){
if (cs[i] == String.class){
args[i] = ObjectUtils.toString(args[i]);
if(StringUtils.endsWith((String)args[i], ".0")){
args[i] = StringUtils.substringBefore((String)args[i], ".0");
}
}else if (cs[i] == Integer.class){
args[i] = ObjectUtils.toInteger(args[i]);
}else if (cs[i] == Long.class){
args[i] = ObjectUtils.toLong(args[i]);
}else if (cs[i] == Double.class){
args[i] = ObjectUtils.toDouble(args[i]);
}else if (cs[i] == Float.class){
args[i] = ObjectUtils.toFloat(args[i]);
}else if (cs[i] == Date.class){
if (args[i] instanceof String){
args[i] = DateUtils.parseDate(args[i]);
}else{
// POI Excel 日期格式转换
args[i] = DateUtil.getJavaDate((Double)args[i]);
}
}
}
}
return (E)method.invoke(obj.getClass() == Class.class ? null : obj, args);
} catch (Exception e) {
String msg = "method: "+method+", obj: "+obj+", args: "+args+"";
throw ReflectUtils.convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 循环向上转型获取对象的DeclaredField并强制设置为可访问
* 如向上转型到Object仍无法找到返回null
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Validate.notBlank(fieldName, "fieldName can't be blank");
Class<?> clazz = obj.getClass();
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
ReflectUtils.makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {//NOSONAR
// Field不在当前类定义,继续向上转型
continue;// new add
}
}
return null;
}
/**
* 循环向上转型获取对象的DeclaredMethod,并强制设置为可访问,
* 如向上转型到Object仍无法找到返回null
* 匹配函数名+参数类型。
* 用于方法需要被多次调用的情况先使用本函数先取得Method然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Class<?> clazz = obj.getClass();
if (clazz == Class.class){
clazz = (Class) obj;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Method method = superClass.getDeclaredMethod(methodName, parameterTypes);
ReflectUtils.makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
// Method不在当前类定义,继续向上转型
continue;// new add
}
}
return null;
}
/**
* 循环向上转型获取对象的DeclaredMethod并强制设置为可访问
* 如向上转型到Object仍无法找到返回null
* 只匹配函数名。
* 用于方法需要被多次调用的情况先使用本函数先取得Method然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Class<?> clazz = obj.getClass();
if (clazz == Class.class){
clazz = (Class) obj;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
Method[] methods = superClass.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
ReflectUtils.makeAccessible(method);
return method;
}
}
}
return null;
}
}