对象映射框架MapStruct对比orika

1、各大对象映射框架性能对比

工具实现方式缺点说明
mapstructgetter/setter方法需要了解注解和配置项语法JSR269注解处理器在编译期自动生成Java Bean转换代码,支持可配置化,扩展性强
orika动态生成字节码首次调用耗时较久,性能适中采用javassist类库生成Bean映射的字节码,之后直接加载执行生成的字节码文件
Spring BeanUtils反射机制不支持名称相同但类型不同的属性转换
Apache BeanUtils反射机制需要处理编译期异常,性能最差
dozer反射机制性能差使用reflect包下Field类的set(Object obj, Object value)方法进行属性赋值
BeanCopier反射机制\1. BeanCopier只拷贝名称和类型都相同的属性。即便基本类型与其对应的包装类型也不能相互转换;使用ASM的MethodVisitor直接编写各属性的get/set方法

就性能而言:mapstruct性能无疑是是最高的,接下来依次是Spring BeanUtils>orika>BeanCopier>dozer>apache BeanUtils

2、MapStruct的使用

2.1、引入pom
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.3.0.Final</version>
    <scope>provided</scope>
</dependency>
2.2 、单个bean映射
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(componentModel = "spring")
public interface OrderConvert {

    @Mapping(source = "id", target = "orderId")
    @Mapping(source = "createTime", target = "orderTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
    OrderDTO from(Order order);

}

测试代码

@Test
public void test() {
    Order order = Order.builder()
        .id(123L)
        .buyerPhone("13707318123")
        .buyerAddress("中电软件园")
        .amount(10000L)
        .payStatus(1)
        .createTime(LocalDateTime.now())
        .build();

    OrderConvert orderConvert = Mappers.getMapper(OrderConvert.class);
    OrderDTO orderDTO = orderConvert.from(order);

    System.out.println("order:    " + order);
    System.out.println("orderDTO: " + orderDTO);
}
2.3、多个bean的映射
@Mapper(componentModel = "spring")
public interface GoodInfoConvert {

    /** Long => String 隐式类型转换 */
    @Mapping(source = "good.id", target = "goodId")
    /** 属性名不同, */
    @Mapping(source = "type.name", target = "typeName")
    /** 属性名不同 */
    @Mapping(source = "good.title", target = "goodName")
    /** 属性名不同 */
    @Mapping(source = "good.price", target = "goodPrice")
    GoodInfoDTO from(GoodInfo good, GoodType type);

}
2.4、参数的含义映射
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Mapper(imports = {CustomMapping.class})
public interface StudentConvert {

    @Mapping(source = "id", target = "studentId")
    @Mapping(source = "name", target = "studentName")
    @Mapping(source = "age", target = "age")
    @Mapping(target = "ageLevel", expression = "java(CustomMapping.ageLevel(student.getAge()))")
    @Mapping(target = "sexName", expression = "java(CustomMapping.sexName(student.getSex()))")
    @Mapping(source = "admissionTime", target = "admissionDate", dateFormat = "yyyy-MM-dd")
    StudentDTO from(Student student);

    default LocalDate map(LocalDateTime time) {
        return time.toLocalDate();
    }

}

自定义的映射类

public class CustomMapping {

    static final String[] SEX = {"女", "男", "未知"};

    public static String sexName(Integer sex) {

        if (sex < 0 && sex > 2){
            throw new IllegalArgumentException("invalid sex: " + sex);
        }
        return SEX[sex];
    }

    public static String ageLevel(Integer age) {
        if (age < 18) {
            return "少年";
        } else if (age >= 18 && age < 30) {
            return "青年";
        } else if (age >= 30 && age < 60) {
            return "中年";
        } else {
            return "老年";
        }
    }

}

3、orika的使用

3.1 引入pom
<dependency>
    <groupId>ma.glasnost.orika</groupId>
    <artifactId>orika-core</artifactId>
    <version>1.5.2</version>
</dependency>
3.2、初始化实例
package tech.chenxing.deploy.configuration;

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 MapperConfig {
    @Bean
    public MapperFactory mapperFactory() {
        return new DefaultMapperFactory.Builder().build();
    }
}
3.3、配置映射对象

定义转换器

public class FlowDocDOConverter extends CustomMapper<FlowDoc, FlowDocBean> {    @Autowired private DocInfoMapperExt docInfoMapperExt;    @Override    public void mapAtoB(FlowDoc flowDocDO, FlowDocBean flowDocBean, MappingContext context) {        if (StringUtils.isNotBlank(flowDocDO.getDocUuid())) {            DocInfo docInfoDO = docInfoMapperExt.getByUUID(flowDocDO.getDocUuid());            ValidationUtil.assertNull(                    docInfoDO,                    new BizFlowManagerException(                            BizFlowManagerBaseResultCodeEnum.FLOW_NOT_EXISTS,                            flowDocDO.getDocUuid()));            flowDocBean.setId(docInfoDO.getId());            flowDocBean.setFileId(docInfoDO.getFileId());            flowDocBean.setName(docInfoDO.getName());            flowDocBean.setDocPassword(docInfoDO.getDocPassword());            flowDocBean.setDocSource(docInfoDO.getDocSource());            flowDocBean.setEncryption(docInfoDO.getEncryption());            flowDocBean.setGmtCreate(flowDocDO.getGmtCreate());            flowDocBean.setGmtModified(flowDocDO.getGmtModified());        }    }}

注入转换器

package tech.chenxing.deploy.configuration;

import ma.glasnost.orika.MapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;


@Component
public class MapperInit {
    @Autowired private MapperFactory mapperFactory;
    @Autowired private FlowDocDOConverter flowDocDOConverter;


    @PostConstruct
    public void init() {
        // 注册文档映射方式
        mapperFactory
                .classMap(User.class, UserDTO.class)
                .field("docUuid", "docId")
                .byDefault() // 剩余的字段映射
                .customize(flowDocDOConverter)
                .register();
    }
}

代码使用

public xxx queryuser() {
        List<User> userList =
                userMapperExt.queryUser();
        List<UserDTO> userDTOList =
                mapperFactory.getMapperFacade().mapAsList(userList, UserDTO.class);
        QueryFlowDocResult queryFlowDocResult = new QueryFlowDocResult();
    }

版权声明:本文为人工博客的原创文章,遵循 CC 4.0 BY+SA 版权协议,转载请附上原文出处链接及本声明。
本文链接:https://www.94rg.com/article/1795

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值