Java对象转换工具-orika
1.概述
Orika是java Bean映射框架,可以实现从一个对象递归拷贝数据至另一个对象,它使用字节码生成器创建开销最小的快速映射,比其他基于反射方式实现更快。对于名称不相同或类型不一样,则需要单独映射。
2.实战演练
2.1环境准备
新建一个SpringBoot的项目,导入需要的依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>
2.2引入orika
1)导入依赖
<dependency> <groupId>ma.glasnost.orika</groupId> <artifactId>orika-core</artifactId> <version>1.5.1</version> </dependency>
2)创建对象UserDto,作为源对象
package com.zxh.test; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class UserDto { private String id; private String name; private Integer age; }
3)创建对象UserVo,作为目标对象
package com.zxh.test; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class UserVo { private String id; private String name; private Integer userAge; }
4)编写容器注入类,避免重复创建映射工厂类
package com.zxh.test.config; import ma.glasnost.orika.MapperFactory; import ma.glasnost.orika.impl.DefaultMapperFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MapperFactoryAutoWire { @Bean public MapperFactory getFactory(){ return new DefaultMapperFactory.Builder().build(); } }
2.3与dozer的比较
由于后面章节会对其方法进行封装,故这里直接与dozer进行对比
//注入 @Resource private ma.glasnost.orika.MapperFactory mapperFactory; @Test public void test() { Integer t = 1000000; List<UserDto> list = new ArrayList<>(); for (int i = 0; i < t; i++) { UserDto userDto = new UserDto("10" + i, "男", 20); list.add(userDto); } StopWatch watch = new StopWatch(); watch.start("orika"); // 因为存在字段不一样,需要手动映射一下。如果所有字段一样,则不用写mapperFactory.classMap()方法 mapperFactory.classMap(UserDto.class, UserVo.class) .field("age", "userAge")//不一样的字段映射,源字段->目标字段 .byDefault() .register(); list.stream().forEach(item -> { UserVo userVo = mapperFactory.getMapperFacade().map(item, UserVo.class); }); watch.stop(); System.out.println("orika复制用时:" + watch.getLastTaskTimeMillis()); watch.start("dozer"); list.stream().forEach(item -> { UserVo userVo = mapper.map(item, UserVo.class); }); watch.stop(); System.out.println("dozer复制用时:" + watch.getLastTaskTimeMillis()); }
打印的结果如下:
在上述的案例中,为了性能的比较,故分别进行100万次的对象复制,可以很明显的看出两者的性能差异,显而易见,orika的性能优于dozer。
那么orika有没有对集合的快速复制呢?答案是有,下面使用普通的foreach和其自带的集合复制进行对比:
@Test public void test9() { Integer t = 100000; List<UserDto> list = new ArrayList<>(); for (int i = 0; i < t; i++) { UserDto userDto = new UserDto("10" + i, "男", 20); list.add(userDto); } StopWatch watch = new StopWatch(); // 因为存在字段不一样,需要手动映射一下。如果所有字段一样,则不用写mapperFactory.classMap()方法 mapperFactory.classMap(UserDto.class, UserVo.class) .field("age", "userAge")//不一样的字段映射,源字段->目标字段 .byDefault() .register(); watch.start("orika1"); list.stream().forEach(item -> { UserVo userVo = mapperFactory.getMapperFacade().map(item, UserVo.class); }); watch.stop(); System.out.println("orika-map复制用时:" + watch.getLastTaskTimeMillis()); watch.start("orika2"); List<UserVo> userVos = mapperFactory.getMapperFacade().mapAsList(list, UserVo.class); watch.stop(); System.out.println("orika-list复制用时:" + watch.getLastTaskTimeMillis()); }
打印的结果如下:
虽然只进行了10万次的复制,但性能就显现出来了。
3.封装使用
package com.zxh.test.util; import ma.glasnost.orika.MapperFactory; import ma.glasnost.orika.metadata.ClassMapBuilder; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; import java.util.Map; import java.util.Set; /** * @author zhongyushi */ @Component public class OrikaUtil { @Resource private MapperFactory mapperFactory; /** * 字段映射 * * @param aType 源对象类型 * @param bType 目标对象类型 * @param fields 不同字段映射值 * @param <A> * @param <B> */ private <A, B> void filedMap(Class<A> aType, Class<B> bType, Map<String, String> fields) { ClassMapBuilder<A, B> mapBuilder = mapperFactory.classMap(aType, bType); if (fields != null && fields.size() > 0) { Set<Map.Entry<String, String>> entries = fields.entrySet(); for (Map.Entry<String, String> entry : entries) { mapBuilder.field(entry.getKey(), entry.getValue()); } } mapBuilder.byDefault().register(); } /** * 对象的复制 * * @param aType 源对象类型 * @param bType 目标对象类型 * @param fields 不同字段映射值 * @param source 要复制的对象 * @param <A> * @param <B> * @return */ public <A, B> B beanCopy(Class<A> aType, Class<B> bType, Map<String, String> fields, A source) { filedMap(aType, bType, fields); B target = mapperFactory.getMapperFacade().map(source, bType); return target; } /** * 对象的复制 * * @param aType 源对象类型 * @param bType 目标对象类型 * @param source 要复制的对象 * @param <A> * @param <B> * @return */ public <A, B> B beanCopy(Class<A> aType, Class<B> bType, A source) { return beanCopy(aType, bType, null, source); } /** * 集合的复制 * * @param aType 源对象类型 * @param bType 目标对象类型 * @param fields 不同字段映射值 * @param source 要复制的对象 * @param <A> * @param <B> * @return */ public <A, B> List<B> beanListCopy(Class<A> aType, Class<B> bType, Map<String, String> fields, Iterable<A> source) { filedMap(aType, bType, fields); List<B> bList = mapperFactory.getMapperFacade().mapAsList(source, bType); return bList; } /** * 集合的复制 * * @param aType 源对象类型 * @param bType 目标对象类型 * @param source 要复制的对象 * @param <A> * @param <B> * @return */ public <A, B> List<B> beanListCopy(Class<A> aType, Class<B> bType, Iterable<A> source) { return beanListCopy(aType, bType, null, source); } }
对其方法进行进一步的封装,在使用的地方注入使用:
@Autowired private OrikaUtil orikaUtil; @Test public void test0() { UserDto userDto = new UserDto("10", "男", 20); Map<String, String> map = new HashMap<>(); map.put("age", "userAge"); UserVo userVo = orikaUtil.beanCopy(UserDto.class, UserVo.class, map, userDto); System.out.println(userVo); } @Test public void test1() { Integer t = 10; List<UserDto> list = new ArrayList<>(); for (int i = 0; i < t; i++) { UserDto userDto = new UserDto("10" + i, "男", 20); list.add(userDto); } Map<String, String> map = new HashMap<>(); map.put("age", "userAge"); System.out.println(orikaUtil.beanListCopy(UserDto.class, UserVo.class, map, list)); }
使用起来也格外的方便。
就是这么简单,你学废了吗?感觉有用的话,给笔者点个赞吧 !