Spring超详细讲解BeanUtils改造

 更新时间:2022年06月21日 11:23:59   作者:llp1110  
BeanUtils.copyProperties();确实为我们做了很多事情,虽然不能完美完成深拷贝,但是对于 po、vo、dto 的拷贝已经足够用了。但是其还是有一些不够完美的地方,下面我们来探讨一下有哪些不足以及改造

1.基本原理

原理:https://www.jb51.net/article/252384.htm

浅拷贝:https://www.jb51.net/article/221283.htm

BeanUtils.copyProperties();确实为我们做了很多事情,虽然不能完美完成深拷贝,但是对于 po、vo、dto 的拷贝已经足够用了。但是其还是有一些不够完美的地方。

不足几点如下:

不能拷贝 list,而拷贝 list 的情况又大量存在,因此会有许多重复代码。

for (S source : sources) {
    T target = new T();
    copyProperties(source, target);
    list.add(target);
}

有一些简单的查询,仅仅需要转换一下 vo 也需要 new Vo()。

public Vo findById(Integer id) {
 Vo vo = new Vo();
 Po po = dao.findById(id);
 copyProperties(po, vo);
 return vo;
}

这种拷贝方式是没有返回值的,jdk8 支持 stream() 操作之后,支持不是很友好,不方便 lambda 表达式的使用,因此我们决定通过集成 BeanUtils 类,自己造一个方便用的轮子。

2.使用

我们将新创建一个工具类 BeanConvertUtils,使用如下,当我们要转换 po、vo 时,只需要:

// 使用前
public Vo findById(Integer id) {
 Vo vo = new Vo();
 Po po = dao.findById(id);
 copyProperties(po, vo);
 return vo;
}
// 使用后
public Vo findById(Integer id) {
 return BeanConvertUtils.converTo(dao.findById(id), Vo::new);
}
// 使用后,通过lambda表达式特殊处理个别字段
public Vo findById(Integer id) {
 return BeanConvertUtils.converTo(dao.findById(id), Vo::new, 
  (s, t) -> t.setName(s.getName))
 );
}

当我们要拷贝 list 的时候也很简单:

// 使用前
public List<Vo> findAll() {
 List<Vo> vos = new ArrayList();
 List<Po> pos = dao.findAll();
 for (Po po : Pos) {
     Vo vo = new Vo();
     BeanUtis.copyProperties(po, vo);
     vos.add(vo);
    }
 return vos;
}
// 使用后
public List<Vo> findAll() {
 return BeanConvertUtils.converToList(dao.findAll(), Vo::new)
}
// 同样支持自定义lambda
public List<Vo> findAll() {
 return BeanConvertUtils.converToList(dao.findAll(), Vo::new,
  (s, t) -> t.setName(s.getName))
 )
}

工具代码如下:

import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
 * Spring-BeanUtils转换对象工具封装(浅拷贝)
 */
public class BeanConvertUtils extends BeanUtils {
    /**
     * 拷贝对象
     
     * @param source
     * @param targetSupplier
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> T convertTo(S source, Supplier<T> targetSupplier) {
        return convertTo(source, targetSupplier, null);
    }
    /**
     * 拷贝list
     *
     * @param sources
     * @param targetSupplier
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> List<T> convertListTo(List<S> sources, Supplier<T> targetSupplier) {
        return convertListTo(sources, targetSupplier, null);
    }
    /**
     * 转换对象
     *
     * @param source         源对象
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象
     */
    public static <S, T> T convertTo(S source, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {
        if (null == source || null == targetSupplier) {
            return null;
        }
        T target = targetSupplier.get();
        copyProperties(source, target);
        if (callBack != null) {
            callBack.callBack(source, target);
        }
        return target;
    }
    /**
     * 转换对象
     *
     * @param sources        源对象list
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象list
     */
    public static <S, T> List<T> convertListTo(List<S> sources, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {
        if (null == sources || null == targetSupplier) {
            return null;
        }
        List<T> list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T target = targetSupplier.get();
            copyProperties(source, target);
            if (callBack != null) {
                callBack.callBack(source, target);
            }
            list.add(target);
        }
        return list;
    }
    /**
     * 回调接口
     *
     * @param <S> 源对象类型
     * @param <T> 目标对象类型
     */
    @FunctionalInterface
    public interface ConvertCallBack<S, T> {
        void callBack(S t, T s);
    }
}

3.性能

由于只是 BeanUtils 的一个封装,跟原来的代码性能几乎差不多,如果要说差一点也没错,毕竟多了一层函数堆栈的调用,但是基本可以忽略不计。主要的性能还是由 BeanUtils 决定。

4.提醒

不知道大家对这个 BeanConvertUtils 工具类感觉怎么样,自己在项目中倒是大量使用,也很方便。

但是有两点要提醒:

  • 此方法依旧不能解决深层次的深拷贝问题,详细的可以 google 一下 BeanUtils 的深拷贝问题。
  • 如果 source 或者 targetSupplier 只要有一个为 null,本工具类不像 BeanUtils 一样抛出异常,而是返回 null,因为笔者认为调用方如果把 null 进行准换,那就是想转换为 null,为不为空应该由调用方自己负责。

到此这篇关于Spring超详细讲解BeanUtils改造的文章就介绍到这了,更多相关Spring BeanUtils内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java十分钟精通进阶适配器模式

    Java十分钟精通进阶适配器模式

    适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能
    2022-04-04
  • JavaWeb 入门:Hello Servlet

    JavaWeb 入门:Hello Servlet

    这篇文章主要介绍了Servlet开发JavaWeb工程示例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • 详解SpringBoot中异步请求的实现与并行执行

    详解SpringBoot中异步请求的实现与并行执行

    这篇文章主要为大家详细介绍了在SpringBoot中如何是实现异步请求、并行执行,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-02-02
  • Java string不可变原理实例解析

    Java string不可变原理实例解析

    这篇文章主要介绍了Java string不可变原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • SpringBoot报错Invalid bound statement (not found)问题排查和解决方案

    SpringBoot报错Invalid bound statement (not found)问题排查和解决方案

    这篇文章主要介绍了SpringBoot报错Invalid bound statement (not found)问题排查和解决方案,文中通过图文结合的方式讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-03-03
  • Java正则表达式的基本用法和实例大全

    Java正则表达式的基本用法和实例大全

    这篇文章主要给大家介绍了关于Java正则表达式的基本用法和实例的相关资料,大家在使用Java正则表达式的时候可查阅这篇文章,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-03-03
  • hadoop中实现java网络爬虫(示例讲解)

    hadoop中实现java网络爬虫(示例讲解)

    下面小编就为大家带来一篇hadoop中实现java网络爬虫(示例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • 详解如何在SpringBoot中优雅地重试调用第三方API

    详解如何在SpringBoot中优雅地重试调用第三方API

    作为后端程序员,我们的日常工作就是调用一些第三方服务,将数据存入数据库,返回信息给前端。本文为大家介绍了如何在SpringBoot中优雅地重试调用第三方API,需要的可以参考一下
    2022-12-12
  • java 代理机制的实例详解

    java 代理机制的实例详解

    这篇文章主要介绍了java 代理机制的实例详解的相关资料,这里说明下如何实现代理机制,帮助大家理解掌握这部分内容,需要的朋友可以参考下
    2017-08-08
  • Spring实战之使用XML方式管理声明式事务操作示例

    Spring实战之使用XML方式管理声明式事务操作示例

    这篇文章主要介绍了Spring实战之使用XML方式管理声明式事务操作,结合实例形式详细分析了Spring XML方式管理声明式事务具体步骤、配置、接口及使用技巧,需要的朋友可以参考下
    2020-01-01

最新评论