• Spring框架对BeanUtils.copyProperties的优化


    前言

    在高并发环境下,我们难免要进行大量的存库操作,而一般的操作是监听kafka然后将消息转换成实体类,再使用一些orm框架(mybatis-plus,jpa等)进行入库,我们在将消息转换的时候难免要用到反射,今天我们来讲讲Spring框架中对BeanUtils.copyProperties的优化

    缓存机制

    Spring 的 BeanUtils 类利用了缓存机制来加速属性的访问。具体来说,它缓存了属性描述符(PropertyDescriptor)以减少反射操作的次数。每次复制属性时,它会先检查缓存,以避免重复地使用反射来获取属性描述符

    private static final Map<Class<?>, PropertyDescriptor[]> propertyDescriptorCache =
            new ConcurrentHashMap<>(256);
    
    

    更高效的反射操作

    Spring 使用了一些优化的反射操作来提高性能,例如:

    快速方法访问:使用 ReflectionUtils 提供的方法快速访问属性。
    避免不必要的反射调用:通过缓存属性描述符和方法访问器,减少反射调用的开销

    更灵活的类型转换

    Spring 的 BeanUtils.copyProperties 支持类型转换,这意味着如果源对象和目标对象的属性类型不完全匹配,Spring 会尝试进行适当的类型转换。这是通过 Spring 的 ConversionService 实现的,它支持复杂的类型转换逻辑

    更好的异常处理

    Spring 的 BeanUtils 提供了更好的异常处理机制。它会捕获并处理各种可能的异常情况,并提供详细的异常信息,帮助开发者更快地发现和解决问题

    支持嵌套属性复制

    Spring 的 BeanUtils.copyProperties 支持嵌套属性的复制,这意味着它可以处理嵌套对象的属性复制,而不仅仅是简单属性。这使得它在处理复杂对象结构时更加灵活和方便。

    支持忽略特定属性

    Spring 的 BeanUtils.copyProperties 允许开发者指定在复制过程中忽略哪些属性。这对于需要部分属性复制的场景非常有用。

    源码分析

    以下是 Spring BeanUtils.copyProperties 方法的简化版源码,以展示其主要优化和特性:

    public static void copyProperties(Object source, Object target) throws BeansException {
        copyProperties(source, target, null, (String[]) null);
    }
    
    private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties)
            throws BeansException {
        
        Assert.notNull(source, "Source must not be null");
        Assert.notNull(target, "Target must not be null");
    
        Class<?> actualEditable = target.getClass();
        if (editable != null) {
            if (!editable.isInstance(target)) {
                throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
                        "] not assignable to Editable class [" + editable.getName() + "]");
            }
            actualEditable = editable;
        }
        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
        List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null;
    
        for (PropertyDescriptor targetPd : targetPds) {
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
                PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (readMethod != null &&
                            ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                        try {
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }
                            Object value = readMethod.invoke(source);
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            writeMethod.invoke(target, value);
                        } catch (Throwable ex) {
                            throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", ex);
                        }
                    }
                }
            }
        }
    }
    
    
  • 相关阅读:
    position left设置居中,除了auto以外,还有什么方式
    APP自动化测试,Appium+PO模式+Pytest框架实战—项目案例
    分类预测 | MATLAB实现WOA-LSTM鲸鱼算法优化长短期记忆网络数据分类预测
    零基础自学javase黑马课程第七天
    vue组件间通信
    python日期计算器 青少年编程电子学会python编程等级考试二级真题解析2021年12月
    直播美颜SDK代码浅析:直播平台接入美颜SDK是怎样实现美颜的?
    X2Keyarch迁移工具实战 | 将CentOS高效迁移至浪潮云峦操作系统KeyarchOS
    LRTimelapse 6 for Mac(延时摄影视频制作软件)
    打家劫舍 III
  • 原文地址:https://blog.csdn.net/u013531166/article/details/139737721