1. 前言

距离上上篇【mica cglib 增强——【01】cglib bean copy 介绍】[1] 已经过去一个月零八天。

距离上一篇【Java Bean Copy 性能大比拼】[2] 已过去一个月零一天。

督促自己早日完成整个系列的文章,今天我将带领大家从字节码的层面来分析。

:对于java 字节码感兴趣的朋友也可以阅读 《Java虚拟机规范》,Oracle 官方也有英文原版[3]的 pdf可供下载。


2. Bean 模型

我们列举2个模型 User 和 UserVo,注意:birthday 字段类型不一样(敲黑板)。


2.1 User


@Datapublic class User {    private Integer id;    private String name;    private Integer age;    private LocalDateTime birthday;}


2.2 UserVo







@Datapublic class UserVo {    private String name;    private Integer age;    private String birthday;}


3. Cglib Bean copy 字节码分析


3.1 配置 Cglib debug 模式

在第一篇【mica cglib 增强——【01】cglib bean copy 介绍】[4]我们提到可以设置 cglib 源码生成目录。




// 设置 cglib 源码生成目录String sourcePath = "/Users/lcm/git/mica/mica-example/web-example/src/test/java";System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, sourcePath);


3.2 Bean copy 时生成的字节码


不使用类型转换时

Bean copy 的代码如下:


// 1. 初始化 user,赋值User user = new User();user.setId(250);user.setName("如梦技术");user.setAge(30);user.setBirthday(LocalDateTime.now());// 2. 初始化 userVoUserVo userVo = new UserVo();// 3. 构造 BeanCopier,不是用类型转换BeanCopier copier = BeanCopier.create(User.class, UserVo.class, false);// 4. 拷贝对象,不是用类型转换,转换器可以使用 nullcopier.copy(user, userVo, null);
// 5. 打印结果:UserVo(name=如梦技术, age=30, birthday=null)System.out.println(userVo);

生成的字节码:


package org.springframework.cglib.empty;
import net.dreamlu.test.User;import net.dreamlu.test.UserVo;import org.springframework.cglib.beans.BeanCopier;import org.springframework.cglib.core.Converter;
public class Object$$BeanCopierByCGLIB$$70f9539b extends BeanCopier {    public Object$$BeanCopierByCGLIB$$70f9539b() {    }
   public void copy(Object var1, Object var2, Converter var3) {        UserVo var10000 = (UserVo)var2;        User var10001 = (User)var1;        var10000.setAge(((User)var1).getAge());        var10000.setName(var10001.getName());    }}

注意: 由于 birthday 字段类型不一样,没有生成 set方法。


使用类型转换时

Bean copy 的代码如下:


// 1. 初始化 user,赋值User user = new User();user.setId(250);user.setName("如梦技术");user.setAge(30);user.setBirthday(LocalDateTime.now());
// 2. 初始化 userVoUserVo userVo = new UserVo();// 3. 构造 BeanCopier,不是用类型转换BeanCopier copier = BeanCopier.create(User.class, UserVo.class, true);// 4. 拷贝对象,不是用类型转换,转换器可以使用 nullcopier.copy(user, userVo, new Converter() {    @Override    public Object convert(Object o, Class aClass, Object o1) {        if (o == null) {            return null;        }        // 直接使用 mica 中的类型转换工具        return ConvertUtil.convert(o, aClass);    }});
// 5. 打印结果:UserVo(name=如梦技术, age=30, birthday=19-4-30 下午9:45)System.out.println(userVo);

生成的字节码:


package org.springframework.cglib.empty;
import net.dreamlu.test.User;import net.dreamlu.test.UserVo;import org.springframework.cglib.beans.BeanCopier;import org.springframework.cglib.core.Converter;
public class Object$$BeanCopierByCGLIB$$70f9539a extends BeanCopier {    private static final Class CGLIB$load_class$java$2Elang$2EInteger;    private static final Class CGLIB$load_class$java$2Elang$2EString;
   public Object$$BeanCopierByCGLIB$$70f9539a() {    }
   public void copy(Object var1, Object var2, Converter var3) {        UserVo var4 = (UserVo)var2;        User var5 = (User)var1;        var4.setAge((Integer)var3.convert(var5.getAge(), CGLIB$load_class$java$2Elang$2EInteger, "setAge"));        var4.setBirthday((String)var3.convert(var5.getBirthday(), CGLIB$load_class$java$2Elang$2EString, "setBirthday"));        var4.setName((String)var3.convert(var5.getName(), CGLIB$load_class$java$2Elang$2EString, "setName"));    }
   static void CGLIB$STATICHOOK1() {        CGLIB$load_class$java$2Elang$2EInteger = Class.forName("java.lang.Integer");        CGLIB$load_class$java$2Elang$2EString = Class.forName("java.lang.String");    }
   static {        CGLIB$STATICHOOK1();    }}

注意: 使用类型转换后生成了 birthday 的 set,仔细观察可以看到使用了类型转换之后生成的字节码都走了类型转换的逻辑。


4 Mica Bean copy的字节码

由于 Mica 的 Bean copy 是基于 Cglib 进行的增强查看字节码的方式和Cglib一样,设置的方式也和上面一样。


4.1 不使用类型转换

Bean copy 的代码如下:


// 1. 初始化 user,赋值User user = new User();user.setId(250);user.setName("如梦技术");user.setAge(30);user.setBirthday(LocalDateTime.now());
// 2. 使用 mica 的 BeanUtil copy 方法UserVo userVo = BeanUtil.copy(user, UserVo.class);
// 3. 打印结果:UserVo(name=如梦技术, age=30, birthday=null)System.out.println(userVo);

生成的字节码:


package org.springframework.cglib.empty;
import net.dreamlu.mica.core.beans.MicaBeanCopier;import net.dreamlu.test.User;import net.dreamlu.test.UserVo;import org.springframework.cglib.core.Converter;
public class Object$$MicaBeanCopierByCGLIB$$aa75e50d extends MicaBeanCopier {    public Object$$MicaBeanCopierByCGLIB$$aa75e50d() {    }
   public void copy(Object var1, Object var2, Converter var3) {        UserVo var4 = (UserVo)var2;        User var5 = (User)var1;        var4.setAge(var5.getAge());        var4.setName(var5.getName());    }}

注意: 不使用类型转换时生成的字节码同 Cglib 一致,只是使用更加简单一些。


4.2 使用类型转换时

Bean copy 的代码如下:


// 1. 初始化 user,赋值User user = new User();user.setId(250);user.setName("如梦技术");user.setAge(30);user.setBirthday(LocalDateTime.now());
// 2. 使用 mica 的 BeanUtil copyWithConvert 方法UserVo userVo = BeanUtil.copyWithConvert(user, UserVo.class);
// 3. 打印结果:UserVo(name=如梦技术, age=30, birthday=19-4-30 下午10:04)System.out.println(userVo);

生成的字节码:


package org.springframework.cglib.empty;
import net.dreamlu.mica.core.beans.MicaBeanCopier;import net.dreamlu.test.User;import net.dreamlu.test.UserVo;import org.springframework.cglib.core.Converter;
public class Object$$MicaBeanCopierByCGLIB$$aa75e0e7 extends MicaBeanCopier {    private static final Class CGLIB$load_class$java$2Elang$2EString;
   public Object$$MicaBeanCopierByCGLIB$$aa75e0e7() {    }
   public void copy(Object var1, Object var2, Converter var3) {        UserVo var4 = (UserVo)var2;        User var5 = (User)var1;        var4.setAge(var5.getAge());        var4.setBirthday((String)var3.convert(var5.getBirthday(), CGLIB$load_class$java$2Elang$2EString, "birthday"));        var4.setName(var5.getName());    }
   static void CGLIB$STATICHOOK1() {        CGLIB$load_class$java$2Elang$2EString = Class.forName("java.lang.String");    }
   static {        CGLIB$STATICHOOK1();    }}

注意: 可以看到 Mica 中对生成的字节码进行了优化,对类型相同的拷贝不使用类型转换。


总结

在 Mica 中笔者对 Bean Copy 进行了大量的优化,包括类型转换优化,链式Bean支持,Map支持等,敢兴趣的朋友可以试用哦。


©著作权归作者所有:来自51CTO博客作者轮子工厂的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. mica cglib 增强——[1]cglib bean copy 介绍
  2. Java Bean Copy 性能大比拼
  3. PHP 入门之一(写到哪、数据类型)
  4. Mysql5.7的varchar类型字段建索引竟然失败
  5. C语言将float拆分为4个hex传输与重组
  6. 各种类型的指针作业解析(C语言)
  7. C语言打印数据的二进制格式-原理解析与编程实现
  8. 定位的类型与应用场景和使用条件
  9. 【mysql】ipv4地址转换为4字节整数

随机推荐

  1. Android SDK r23
  2. ListView实用参数
  3. Android开发网站被封解决方案
  4. Android 第三方库混淆proguard-rules,持续
  5. QT android platform SDK installed erro
  6. 如何查看USB方式连接Android设备的外接设
  7. Android SDK 源代码编译
  8. android webrtc构建过程
  9. 谁说Android的动画不廉价(三)之共享元素动
  10. 浅谈Android中的线程的通信及Handle机制