首页 > 其他分享 >求求你不要在使用BeanUtils进行拷贝了

求求你不要在使用BeanUtils进行拷贝了

时间:2023-08-27 16:32:25浏览次数:38  
标签:求求 mapstruct MapStruct 使用 org 拷贝 BeanUtils 指北君

哈喽,大家好,我是指北君

最近接手一个项目发现有些接口只是做了一些简单的单表查询业务,但是却耗时八百多毫秒,明显不太正常, 经排查发现时间都消耗在Apache的BeanUtils中对属性的拷贝上,整个流程使用了四次拷贝方法, 使得整个方法耗时急剧增加。指北君在这里求求大家不要再使用BeanUtils进行拷贝了,那使用什么呢?当然是今天的主角MapStruct。

如何引入

MapStruct引入相当简单。

如果你的项目使用Maven进行管理则添加以下配置:

<properties>
    <org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

如果你的项目使用Gradle进行管理则添加以下配置:

plugins {
    id 'net.ltgt.apt' version '0.20'
}
// 根据你的编译器选择
apply plugin: 'net.ltgt.apt-idea'
// or
apply plugin: 'net.ltgt.apt-eclipse'

dependencies {
    implementation "org.mapstruct:mapstruct:${mapstructVersion}"
    annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"

    // If you are using mapstruct in test code
    testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
}

这样就引入完成了。这里有两种使用方式,可以结合Spring进行使用,也可以不依赖Spring。如下示例:

如何使用

不依赖Spring方式

@Mapper
public interface CarMapper {
    //通过这个静态属性就能调用相应的方法
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);

    CarDto carToCarDto(Car car);
}

与Spring结合使用

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

    CarDto carToCarDto(Car car);
}

通过componentModel参数指定使用Spring的依赖注入方式使用。

当然了如果结合Spring使用也可以统一配置

如何转换

接下来我们进行简单的使用。相同字段自动映射,如果两个实体字段名相同,MapStruct就会自动通过相应的Getter/Setter生成属性拷贝方法, 并且自动忽略不相同的字段。使用方式和BeanUtils相似。

@Mapper
public interface CarMapper {
    CarDto carToCarDto(Car car);
}

MapStruct是在编译期对添加了@Mapper的接口进行生成的实现类,所以上面的代码会生成一个下面的实现类。是不是很简单呢,这样即保证了拷贝的性能,同时我们不需要在业务代码中写对应的拷贝方法,岂不美哉。

当然了,这时候你可能会想,那如果我两个实体映射时有些字段名不一致怎么办呢?

@Mapper
public interface CarMapper {
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}

我们可以通过在方法上添加@Mapping注解指定以下映射关系就可以了,来我们看下效果吧。可以看到我们指定的把numberOfSeats映射成seatCount也很简单的完成了。

MapStruct还有一个更加强大的功能,就是如果映射的类型不一样可以自动转换,常见的数据类型几乎都能支持。我们也一起来看一下吧。

从图中我们可以看到其实并不是很智能,而且转换可能并不是我们想要的,比如说我们要把一个 String类型的时间戳转换为Date类型,并且可能存在BUG,比如说我们想要把String类型的价格转换为BigDecimal类型, 如果这个Price是一个空字符串,那么这里就会报错。

那这怎么办呢?指北君在最后给大家准备了我演示的完整源码和教程。像集合的映射,实体反映射,自定义映射规则,填充默认值等等,教程都有写。

我们已经了解了如何使用,那么真正的效果如何呢?

效果如何

指北君在这里也给大家精心准备了各个拷贝方式的直观对比图。

编辑搜图

从图中可以看到,使用MapStruct提升速度的效果还是蛮显著的。

指北君有话说

当然了MapStruct的骚操作还是挺多的,几乎能满足90%的需要。剩下的10%很大可能是你设计有问题。但由于内容太多,全部展示出来有点啰嗦。如果你感兴趣可以按照下面提供的方式获取相关资源。如果有什么不明白的地方也可以在群里直接咨询我们。指北君也是知无不言言无不尽。

关注公众号 [程序员了不起]回复[eee113] 即可获取navicat绿版。


标签:求求,mapstruct,MapStruct,使用,org,拷贝,BeanUtils,指北君
From: https://blog.51cto.com/u_16231677/7253676

相关文章

  • java高频面试题(反射、对象拷贝)
    java高频面试题(反射、对象拷贝)什么是反射?反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力Java反射:在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法Java反射机制主要提供了以下功能:在运行时判断任意一个......
  • 解放生产力orm并发更新下应该这么处理求求你别再用UpdateById了
    合集-easy-query(7) 1.献给转java的c#和java程序员的数据库orm框架05-222.javaer你还在手写分表分库?来看看这个框架怎么做的干货满满05-263.你没见过的分库分表原理解析和解决方案(一)06-074.你没见过的分库分表原理解析和解决方案(二)06-305.我真的不想再用mybatis和其......
  • 浅拷贝、深拷贝
    理解1、浅拷贝:是对目标的简单复制。只能复制目标对象的值引用,并没有重新开辟新的存储空间,这导致只要其中一方值被修改,另一个也跟着被修改了值。2、深拷贝:内存地址是自主分配的,两个数据指向了不同的地址,数据元素发生改变时不会相互影响。不过,拷贝一般只针对Array和Object先来......
  • .bat执行拷贝和写入文件
    echooff::设置utf-8编码chcp65001::先删除web_out目录下的所有文件及子目录cd../web_outdel/Q/F/S*&rd/S/Q.::进入源代码路径中cd../source_code::执行打包命令callnpmrunbuild::进入dist文件中cddist::执行拷贝命令robocopy...\..\web_ou......
  • C++拷贝构造、赋值函数
    拷贝构造拷贝构造就是一种特殊版本的构造函数,格式:类名(const类名&that){    //执行给每个成员变量进行赋值  }什么时候会调用拷贝构造:当使用旧对象(已new的)给新对象(新new的)初始化时,会自动调用拷贝构造    Testt1;//调用无参构造Testt2=t1......
  • Java的深拷贝与浅拷贝的区别
    1、二者的区别浅拷贝:在拷贝一个对象时,对对象的基本数据类型的成员变量进行拷贝,但对引用类型的成员变量只进行引用的传递,并没有创建一个新的对象,当对引用类型的内容修改会影响被拷贝的对象。深拷贝:在拷贝一个对象时,除了对基本数据类型的成员变量进行拷贝,对引用类型的成员变量进行......
  • C#深拷贝
    最近在做winform项目,遇到页面上有同一个数据源的两个ComboBox,此时操作一个ComboBox,会影响到另一个ComboBox,究其原因,是因为数据源是引用类型,值栈引堆,虽然是不同的ComboBox,但是指针指向同一个内存地址,所以操作一个变量会影响到另一个,为解决这个问题,考虑使用深拷贝的方式。下边是我......
  • C# 深拷贝和浅拷贝的区别
    含义:深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。假设B复制了A,修改A的时候,看B是否发生变化:如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)浅拷贝(shallowCopy)只复制了原......
  • 解放生产力orm并发更新下应该这么处理求求你别再用UpdateById了
    解放生产力orm并发更新下应该这么处理求求你别再用UpdateById了背景很多时候为了方便我们都采用实体对象进行前后端的数据交互,然后为了便捷开发我们都会采用DTO对象进行转换为数据库对象,然后调用UpdateById将变更后的数据存入到数据库内,这样的一个做法有什么问题呢,如果你的......
  • Linux常用命令_拷贝移动、打包压缩、文本编辑命令(cp、mv、tar、vim)
                ......