距離上上篇【mica cglib 加強——【01】cglib bean copy 介紹】 已通過去一個月八一天。html
距離上一篇【Java Bean Copy 性能大比拼】 已過去一個月零一天。vue
督促本身早日完成整個系列的文章,今天我將帶領你們從字節碼的層面來分析。java
注
:對於java 字節碼感興趣的朋友也能夠閱讀 《Java虛擬機規範》,Oracle 官方也有英文原版的 pdf可供下載。git
咱們列舉2個模型 User
和 UserVo
,注意:birthday
字段類型不同(敲黑板)。github
@Data public class User { private Integer id; private String name; private Integer age; private LocalDateTime birthday; }
@Data public class UserVo { private String name; private Integer age; private String birthday; }
在第一篇【mica cglib 加強——【01】cglib bean copy 介紹】咱們提到能夠設置 cglib 源碼生成目錄。web
// 設置 cglib 源碼生成目錄 String sourcePath = "/Users/lcm/git/mica/mica-example/web-example/src/test/java"; System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, sourcePath);
Bean copy 的代碼以下:spring
// 1. 初始化 user,賦值 User user = new User(); user.setId(250); user.setName("如夢技術"); user.setAge(30); user.setBirthday(LocalDateTime.now()); // 2. 初始化 userVo UserVo userVo = new UserVo(); // 3. 構造 BeanCopier,不是用類型轉換 BeanCopier copier = BeanCopier.create(User.class, UserVo.class, false); // 4. 拷貝對象,不是用類型轉換,轉換器能夠使用 null copier.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
方法。oracle
Bean copy 的代碼以下:框架
// 1. 初始化 user,賦值 User user = new User(); user.setId(250); user.setName("如夢技術"); user.setAge(30); user.setBirthday(LocalDateTime.now()); // 2. 初始化 userVo UserVo userVo = new UserVo(); // 3. 構造 BeanCopier,不是用類型轉換 BeanCopier copier = BeanCopier.create(User.class, UserVo.class, true); // 4. 拷貝對象,不是用類型轉換,轉換器能夠使用 null copier.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
,仔細觀察能夠看到使用了類型轉換以後生成的字節碼都走了類型轉換的邏輯。
因爲 Mica 的 Bean copy 是基於 Cglib 進行的加強查看字節碼的方式和Cglib同樣,設置的方式也和上面同樣。
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
一致,只是使用更加簡單一些。
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支持等,敢興趣的朋友能夠試用哦。
示例項目
:https://github.com/lets-mica/mica-example Avue
一款基於vue可配置化的神奇框架:https://gitee.com/smallweigit/avue pig
宇宙最強微服務(架構師必備):https://gitee.com/log4j/pig SpringBlade
完整的線上解決方案(企業開發必備):https://gitee.com/smallc/SpringBlade IJPay
支付SDK讓支付觸手可及:https://gitee.com/javen205/IJPay 掃描上面二維碼,更多精彩內容天天推薦!