首页 > 技术文章 > Beanutils.copyProperties( )的使用与优化

technologykai 2018-07-17 14:25 原文

1.使用原因

   因为现在都是前后端分离所以我们在响应APP端或者前端的时候会维护一套VO,那么DTO到VO的转换便是一堆get... set...这样的代码,比如好几个地方用到的话还要去复制粘贴来转换。所以这里的我就开始动脑子了。

2.解决问题

 刚开始项目中是好几个地方在用,然后我就想把这段VO转换的代码抽取出来,先是想写个工具类,后来一想这是业务的代码。然后就写了一个抽象类。正好让其他接口直接继承。完美解决。

然后是发现VO转换的地方很多,有没有更方便的转换方法? 要不然一堆代码岂不是很掉价

3.使用Beanutils

这里使用的是 org.springframework.beans包下的copyProperties( )方法,他会把字段相同的Bean字段赋值,大大减少了代码量,但从其他程序员的建议说,这个操作会响应性能,数据量大的时候还没有直接get ,set性能好。

4.优化

这里是参考了这个大神的博客,ReflectASM,高性能的反射。 使用的话需要引入下面的依赖。

<!-- https://mvnrepository.com/artifact/com.esotericsoftware.reflectasm/reflectasm -->
<dependency>
<groupId>com.esotericsoftware.reflectasm</groupId>
<artifactId>reflectasm</artifactId>
<version>1.05</version>
</dependency>

ReflectASM是一个很小的java类库,主要是通过asm生产类来实现java反射,执行速度非常快。
大家如果想优化的话,可以试试下面的方法。


  1. public static void main(String[] args) {    
  2.         User user = new User();    
  3.         //使用reflectasm生产User访问类    
  4.         MethodAccess access = MethodAccess.get(User.class);    
  5.         //invoke setName方法name值    
  6.         access.invoke(user, "setName", "张三");    
  7.         //invoke getName方法 获得值    
  8.         String name = (String)access.invoke(user, "getName", null);    
  9.         System.out.println(name);    
  10.     }    
原理 
   上面代码的确实现反射的功能,代码主要的核心是 MethodAccess.get(User.class); 
看了下源码,这段代码主要是通过asm生产一个User的处理类 UserMethodAccess(这个类主要是实现了invoke方法)的ByteCode,然后获得该对象,通过上面的invoke操作user类。 

 

ASM反射转换:

 

[java] view plain copy
 
 
 
 
    1. private static Map<Class, MethodAccess> methodMap = new HashMap<Class, MethodAccess>();  
    2.   
    3.     private static Map<String, Integer> methodIndexMap = new HashMap<String, Integer>();  
    4.   
    5.     private static Map<Class, List<String>> fieldMap = new HashMap<Class, List<String>>();  
    6.   
    7.     public static void copyProperties(Object desc, Object orgi) {  
    8.         MethodAccess descMethodAccess = methodMap.get(desc.getClass());  
    9.         if (descMethodAccess == null) {  
    10.             descMethodAccess = cache(desc);  
    11.         }  
    12.         MethodAccess orgiMethodAccess = methodMap.get(orgi.getClass());  
    13.         if (orgiMethodAccess == null) {  
    14.             orgiMethodAccess = cache(orgi);  
    15.         }  
    16.   
    17.         List<String> fieldList = fieldMap.get(orgi.getClass());  
    18.         for (String field : fieldList) {  
    19.             String getKey = orgi.getClass().getName() + "." + "get" + field;  
    20.             String setkey = desc.getClass().getName() + "." + "set" + field;  
    21.             Integer setIndex = methodIndexMap.get(setkey);  
    22.             if (setIndex != null) {  
    23.                 int getIndex = methodIndexMap.get(getKey);  
    24.                 // 参数一需要反射的对象  
    25.                 // 参数二class.getDeclaredMethods 对应方法的index  
    26.                 // 参数对三象集合  
    27.                 descMethodAccess.invoke(desc, setIndex.intValue(),  
    28.                         orgiMethodAccess.invoke(orgi, getIndex));  
    29.             }  
    30.         }  
    31.     }  
    32.   
    33.     // 单例模式  
    34.     private static MethodAccess cache(Object orgi) {  
    35.         synchronized (orgi.getClass()) {  
    36.             MethodAccess methodAccess = MethodAccess.get(orgi.getClass());  
    37.             Field[] fields = orgi.getClass().getDeclaredFields();  
    38.             List<String> fieldList = new ArrayList<String>(fields.length);  
    39.             for (Field field : fields) {  
    40.                 if (Modifier.isPrivate(field.getModifiers())  
    41.                         && !Modifier.isStatic(field.getModifiers())) { // 是否是私有的,是否是静态的  
    42.                     // 非公共私有变量  
    43.                     String fieldName = StringUtils.capitalize(field.getName()); // 获取属性名称  
    44.                     int getIndex = methodAccess.getIndex("get" + fieldName); // 获取get方法的下标  
    45.                     int setIndex = methodAccess.getIndex("set" + fieldName); // 获取set方法的下标  
    46.                     methodIndexMap.put(orgi.getClass().getName() + "." + "get"  
    47.                             + fieldName, getIndex); // 将类名get方法名,方法下标注册到map中  
    48.                     methodIndexMap.put(orgi.getClass().getName() + "." + "set"  
    49.                             + fieldName, setIndex); // 将类名set方法名,方法下标注册到map中  
    50.                     fieldList.add(fieldName); // 将属性名称放入集合里  
    51.                 }  
    52.             }  
    53.             fieldMap.put(orgi.getClass(), fieldList); // 将类名,属性名称注册到map中  
    54.             methodMap.put(orgi.getClass(), methodAccess);  
    55.             return methodAccess;  
    56.         }  
    57.     }  

参考---https://blog.csdn.net/w05980598/article/details/79134379

推荐阅读