关于BeanUtils 那点屌事

今天出现一个线上bug,我在排查代码的时候,两个高开在我身后陪我排查代码,慌的一批,害怕让他们看见不爽的代码,结果还真发现了,然后被屌了,如下

 List<StudentB> studentbList = new ArrayList<>();
        studentAList.forEach(student->{
            StudentB studentB = new StudentB();
            studentB.setName(student.getName());
            studentB.setAddress(student.getAddress());
            studentB.setAge(student.getAge());
            studentB.setEmail(student.getEmail());
            studentbList.add(studentB);
        });

不过,这段代码也确实该屌,写的确实是烂,问我为什么这么写,我说apache 和spring 的BeanUtils存在一些问题,然后问我什么问题,我简单说了一下

apache 中的BeanUtils 太复杂,导致性能太差

spring 中的BeanUtils 存在一些问题,如下(关于这个,这篇文件写的不错https://www.jianshu.com/p/357b55852efc

  1. Spring的BeanUtils的CopyProperties方法需要对应的属性有getter和setter方法;

  2. 如果存在属性完全相同的内部类,但是不是同一个内部类,即分别属于各自的内部类,则spring会认为属性不同,不会copy;

  3. 泛型只在编译期起作用,不能依靠泛型来做运行期的限制;

  4. 最后,spring和apache的copy属性的方法源和目的参数的位置正好相反,所以导包和调用的时候都要注意一下。

然后就是接着另一顿屌

重点来了,两个高开大佬,给我推荐了一个新的框架,hutools(糊涂),这个是官网 https://hutool.cn/

然后我就看了下文档,重新写了一个

public class ObjectCopyUtils {
    
  static {
        ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
        converterRegistry.putCustom(String.class, StringConvert.class);
    }

     public static void copyProperties(Object sourceData, Object targetData) {
        BeanUtil.copyProperties(sourceData, targetData, true);
    }
 private static class StringConvert implements Converter<String> {

        @Override
        public String convert(Object value, String defaultValue) throws IllegalArgumentException {
            if (null == value) {
                return null;
            }
            if (value instanceof CharSequence) {
                return value.toString();
            } else if (ArrayUtil.isArray(value)) {
                return ArrayUtil.toString(value);
            } else if (CharUtil.isChar(value)) {
                //对于ASCII字符使用缓存加速转换,减少空间创建
                return CharUtil.toString((char) value);
            }
            return value.toString();
        }
    }
}

//第一段代码修改以后
List<StudentB> studentbList = new ArrayList<>();
        studentAList.forEach(student->{
            StudentB studentB = new StudentB();
            ObjectCopyUtils.copyProperties(student,studentB);
            studentbList.add(studentB);
        });

如上

在调用hutools 的BeanUtil方法时,最终回调了内部类SpringConvert的convert方法,能够根据不通的类型,做出不同的判断

分析:

这里面主要包含这几个类: ConverterRegistry  转换登记中心   StringConvert 字符串类型转换类   BeanUtil bean的工具类   BeanCopier 拷贝执行类

执行过程

1. 首先ObjectCopyUtils 初始化时会初始化一个字符串类型的转化类,并且注册到ConverterRegistry转换注册登记中心,并put到一个Map中,在put的时候还是使用了双重检查锁做并发控制

2. 执行拷贝动作,先调用自定义方法 ObjectCopyUtils的的copyProperties方法,copyProperties调用hutools包内的BeanUtil.copyPerties方法,

BeanUtil.copyPerties 再调用BeanCopier的创建方法,创建BeanCopier实例,最后再调用到copy方法

 

我刚才的那个类src不是 provider ,也不是map,而dest 也不是map,多以会调用到beanToBean,beanToBean 会带用到valProviderBean,接着会通过BeanValueProvider 调用ConverterRegistry,根据类型查找,是否有对应转换器,如果找到,则执行转换方法,如果找不到,则执行默认转换方法

有一点还需要注意,bean在拷贝时,src和desc 必须都是带get和set方法的,若是不带,则属性必须为public 类型,否则拷贝会有问题

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值