用了一下BeanUtils.copyPropertie和PropertyUtils.copyProperties()的方法,发现其效率非常低。
原理是通过JDK自带的反射机制动态的去get,set从而去转换我们的类。
使用ASM框架来动态生成
ASM 让我们有能力在运行的过程中动态生成一个新的类并加载和运行它。
ASM是一个通用的 Java 字节码操控和分析框架。它可以用于修改已有的类也可以直接生成类。
主要作用是提高反射的性能。
AOP的实现跟字节码操控密切相关,SpringAOP 是基于动态代理和CGLIB实现的,而CGLIB是基于ASM实现的。所以我们非常有必要学习字节码操控技术。这个领域使用最广泛的框架就是ASM。
MethodAccess中传递的是方法的索引,而不是方法名称。
ReflectASM-invoke,高效率java反射机制原理
前段时间在设计公司基于netty的易用框架时,很多地方都用到了反射机制。反射的性能一直是大家有目共睹的诟病,相比于直接调用速度上差了很多。但是在很多地方,作为未知通用判断的时候,不得不调用反射类型来保障代码的复用性和框架的扩展性。所以我们只能想办法优化反射,而不能抵制反射,那么优化方案,这里给大家推荐了ReflectASM。
实际上ReflectASM就是把类的各个方法缓存起来,然后通过case选择,直接调用,因此速度会快上很多。但是它的get方法同样会消耗很大的时间,因此就算是使用ReflectASM的朋友也记得请在启动的时候就初始化get方法计入缓存。
//BeanEntity beanEntityASM = new BeanEntity();
//使用reflectasm生产User访问类
//MethodAccess methodAccess = MethodAccess.get(BeanEntity.class);
//invoke()方法,执行指定的方法,某个对象,方法名,参数;如果参数为空,直接为null;
//methodAccess.invoke(beanEntityASM, "setName", "张三");
//String name = (String) methodAccess.invoke(beanEntityASM, "getName", null);
//System.out.println(name);
//invoke()方法,执行指定的方法,某个对象,方法名,参数;如果参数为空,直接为null;
//通过类的Class对象创建对象
//MethodAccess,返回当前对象的MethodAccess类,主要用于操作当前对象。
//如何获取一个当前对象的MethodAccess对象?
//ASM:Java字节码操控框架,可以大幅度提高反射的性能。二进制字节码操作类
//把类当做一个数组,方法的位置就是索引。MethodAccess的作用:获取某个方法在类中的索引。把类当做数组。
/**
* 属性copy类原理
*
* @param target 目标
* @param source 源对象
*/
public static void copyProperties(Object target, Object source) {
//获取指定对象的MethodAccess
MethodAccess targetMethodAccess = methodMap.get(target.getClass());
if (targetMethodAccess == null) {
//这行代码是做什么的?
targetMethodAccess = cache(target);
}
MethodAccess sourceMethodAccess = methodMap.get(source.getClass());
if (sourceMethodAccess == null) {
sourceMethodAccess = cache(source);
}
//获取所有的字段集合
List<String> fieldList = fieldMap.get(source.getClass());
for (int i = 0; i < fieldList.size(); i++) {
String getKey = source.getClass().getName() + "." + "get" + fieldList.get(i);
String setkey = target.getClass().getName() + "." + "set" + fieldList.get(i);
Integer setIndex = methodIndexMap.get(setkey);
if (setIndex != null) {
int getIndex = methodIndexMap.get(getKey);
// 参数一需要反射的对象
// 参数二class.getDeclaredMethods 对应方法的index
// 参数对三象集合
//获取原对象的值
Object obj = sourceMethodAccess.invoke(source, getIndex);
//把值设置到目标对象的属性上
targetMethodAccess.invoke(target, setIndex.intValue(), obj);
}
}
}
// 单例模式
private static MethodAccess cache(Object orgi) {
synchronized (orgi.getClass()) {
MethodAccess methodAccess = MethodAccess.get(orgi.getClass());
//获取当前对象的公共的字段
Field[] fields = orgi.getClass().getDeclaredFields();
//创建集合的时候,指定集合的长度,防止集合扩容。
ArrayList<String> fieldList = new ArrayList<>(fields.length);
for (Field field : fields) {
//如果当前属性的访问修饰符是私有或者静态(//是否是私有的,是否是静态的;私有才会有get和set方法)
if (Modifier.isPrivate(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())) {
//驼峰命名法,首字母大写,获取属性名称
String fieldName = StringUtils.capitalize(field.getName());
//获取get方法的索引或者说下标
int getIndex = methodAccess.getIndex("get" + fieldName);
// 获取set方法的下标
int setIndex = methodAccess.getIndex("set" + fieldName);
//获取当前class的类名,// 将类名get方法名,方法下标注册到map中
methodIndexMap.put(orgi.getClass().getName() + "." + "get" + fieldName, getIndex);
methodIndexMap.put(orgi.getClass().getName() + "." + "set" + fieldName, setIndex);
// 将属性名称放入集合里
fieldList.add(fieldName);
}
}
//将类名、属性名称注册到map中
fieldMap.put(orgi.getClass(), fieldList);
methodMap.put(orgi.getClass(), methodAccess);
return methodAccess;
}
}
9575

被折叠的 条评论
为什么被折叠?



