Orika JavaBean映射工具使用
字数 991 2025-08-11 08:36:13
Orika JavaBean映射工具使用指南
1. Orika简介
Orika是一个简单、快速的JavaBean拷贝框架,能够递归地将数据从一个JavaBean复制到另一个JavaBean,这在多层应用开发中非常有用。
1.1 为什么要使用Orika
在开发中,我们经常需要:
- 将对象转换成不同形式以适应不同API
- 在不同业务层中传输对象而不同分层的对象存在不同格式
传统方式的问题:
- Java反射:性能问题、无法解决嵌套JavaBean映射复制
- 手工映射:硬编码、代码量大
- 序列化方式:通过JSON/XML序列化和反序列化,字段参数不同时需要硬编码赋值
2. 常用JavaBean映射技术对比
2.1 BeanUtils
- Apache和Spring的BeanUtils
- 原理:使用
java.beans.Introspector获取属性信息及get/set方法,通过反射进行赋值 - 特点:
- Apache支持名称相同但类型不同的属性转换
- Spring支持忽略某些属性不进行映射
- 都设置了缓存保存已解析过的BeanInfo信息
2.2 BeanCopier
- Cglib的BeanCopier
- 原理:使用ASM的MethodVisitor直接编写各属性的get/set方法生成class文件
- 特点:性能比反射方式的BeanUtils高
2.3 Orika
- 底层使用javassist类库生成Bean映射的字节码
- 特点:
- 速度比反射快很多
- 支持递归映射
- 能处理对象中的递归引用
3. Orika使用详解
3.1 Maven依赖
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.2</version>
</dependency>
3.2 基本映射
3.2.1 字段名相同映射
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
// 字段名相同映射
mapperFactory.classMap(Person.class, PersonInfo.class).byDefault().register();
MapperFacade mapperFacade = mapperFactory.getMapperFacade();
Person person = new Person();
person.setFirstName("张");
person.setLastName("三");
PersonInfo personInfo = mapperFacade.map(person, PersonInfo.class);
3.2.2 字段名不同映射
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(Person.class, PersonDesc.class)
.field("firstName", "givenName")
.field("lastName", "sirName")
.byDefault()
.register();
MapperFacade mapperFacadeDesc = mapperFactory.getMapperFacade();
Person personNew = new Person();
personNew.setFirstName("王");
personNew.setLastName("五");
PersonDesc personDesc = mapperFacadeDesc.map(personNew, PersonDesc.class);
3.3 复杂映射
3.3.1 数组和List映射
public static class PersonNameList {
private List<String> nameList;
// 构造方法和getter/setter
}
mapperFactory.classMap(PersonNameList.class, Person.class)
.field("nameList[0]", "firstName")
.field("nameList[1]", "lastName")
.register();
List<String> nameParts = Arrays.asList(new String[]{"李", "四"});
Person person = mapperFactory.getMapperFacade().map(new PersonNameList(nameParts), Person.class);
3.3.2 相同类型JavaBean复制(原型模式)
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(Person.class, Person.class).byDefault().register();
Person person = new Person();
person.setFirstName("张");
person.setLastName("三");
Person personNew = mapperFactory.getMapperFacade().map(person, Person.class);
3.3.3 嵌套JavaBean映射
mapperFactory.classMap(Flight.class, Flight.class).byDefault().register();
Cabin cabinY = new Cabin("Y", "8", 1200);
Cabin cabinF = new Cabin("C", "6", 1900);
Cabin cabinC = new Cabin("F", "A", 2400);
Flight flight = new Flight("CA1831", Lists.newArrayList(cabinY, cabinF, cabinC));
Flight flightCopy = mapperFactory.getMapperFacade().map(flight, Flight.class);
3.3.4 List类型映射
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(Cabin.class, CabinDesc.class).byDefault().register();
Cabin cabinY = new Cabin("Y", "8", 1200);
Cabin cabinF = new Cabin("C", "6", 1900);
Cabin cabinC = new Cabin("F", "A", 2400);
List<Cabin> cabinList = Lists.newArrayList(cabinY, cabinF, cabinC);
List<CabinDesc> cabinDescList = mapperFactory.getMapperFacade().mapAsList(cabinList, CabinDesc.class);
3.4 自定义数据类型转换器
3.4.1 String转Date
public static class StringToDateConverter extends CustomConverter<String, Date> {
private String dateFormat;
public StringToDateConverter(String dateFormat) {
this.dateFormat = dateFormat;
}
public Date convert(String s, Type<? extends Date> type, MappingContext mappingContext) {
try {
return DateUtils.parseDate(s, dateFormat);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
// 使用
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.getConverterFactory().registerConverter(new StringToDateConverter("yyyy-MM-dd"));
mapperFactory.classMap(ArrayMapper.PersonNameList.class, Person.class)
.field("nameList[0]", "firstName")
.field("nameList[1]", "lastName")
.field("nameList[2]", "birthDate")
.register();
List<String> nameParts = Arrays.asList(new String[]{"李", "四", "1989-10-11"});
Person person = mapperFactory.getMapperFacade().map(new ArrayMapper.PersonNameList(nameParts), Person.class);
4. 性能对比
测试方法:
- 每种方法先预热执行20次
- 再执行100000次获取每次执行的平均时间
性能排序(从快到慢):
- Orika(字节码生成)
- BeanCopier(ASM生成字节码)
- BeanUtils(反射)