基于CGLIB高性能LIST集合对象复制工具类

1.前言

      java开发少不了RO、DTO、VO之类的对象复制,大部分都是基于各类框架提供的方法,比如

CGLIB 
dozer
orika
Apache BeanUtils
Apache PropertyUtil
Spring BeanUtils

之类的,性能上最强的目前不容置疑的是CGLIB,和手动set、get速度基本一致,甩其他工具几条街,但可能是我用的不熟悉,始终没有找到可以复制list集合对象的方法。

所以在这里我自己手动扩展了下,代码不算优雅,但性能上比其他工具类强上很多。

2.CGLIB

    private static final ConcurrentHashMap<String, BeanCopier> mapCaches = new ConcurrentHashMap<>();
    
    /**
     *
     * @param source 原数据,list集合
     * @param target 接收复制的数据实体类属性,会自动转换成list集合
     * @param sourceKey 原数据的实体类属性,为了防止空数据获取该属性报错
     * @param <O>
     * @param <T>
     * @return
     */
    public static <O, T> List<T> listCopyMapper(List<O> source, T target, O sourceKey) {
        String baseKey = generateKey(sourceKey.getClass(), target.getClass());
        BeanCopier copier;
        if (!mapCaches.containsKey(baseKey)) {
            copier = BeanCopier.create(sourceKey.getClass(), target.getClass(), false);
            mapCaches.put(baseKey, copier);
        } else {
            copier = mapCaches.get(baseKey);
        }
        List<T> targets = new ArrayList<>();
        try {
            source.stream().forEach(
                    bean -> {
                        T instance = null;
                        try {
                            instance = (T) target.getClass().getDeclaredConstructor().newInstance();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (InstantiationException e) {
                            e.printStackTrace();
                        }
                        copier.copy(bean, instance, null);
                        targets.add(instance);
                    }
            );
        } catch (Exception e) {
            log.error("list bean复制失败" + e.getMessage());
        }
        return targets;
    }

开启服务器一条数据简单测试了下,一次替换大概在6万纳秒左右,有时候会波动下,但大概不变。

同样的替换成spring的BeanUtils,大概在13万纳秒左右,偶尔波动到20多万纳秒。

偶然发现了orika有个直接复制list的,工具类大概长这样

import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;

import java.util.List;

public class MapperUtils {

	static {
		mapperFactory = new DefaultMapperFactory.Builder().build();
	}

	private static MapperFactory mapperFactory;

	public static <S, D> List<D> mapAsList(Iterable<S> source, Class<D> destinationClass) {
		return mapperFactory.getMapperFacade().mapAsList(source, destinationClass);
	}
}

引入jar


            <dependency>
                <groupId>ma.glasnost.orika</groupId>
                <artifactId>orika-core</artifactId>
                <version>1.5.2</version>
            </dependency>

这个封装的不错,但实际性能就差强人意了,基本18、20w纳秒出头,有时候能蹦到30w纳秒,这还是在静态代码块提前创建mapperFactory的情况下,如果在使用的时候创建,那速度基本没眼看了。

大量数据可能性能上会有偏差,但我没空测试了,仅供参考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java中,使用CGLIB动态代理可以在运行时动态地创建类和对象。通过动态代理,可以为原始对象添加新属性并为其赋值。下面是一个使用CGLIB动态代理实现动态添加属性的工具类示例: ``` import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import net.sf.cglib.beans.BeanGenerator; import net.sf.cglib.beans.BeanMap; public class DynamicBeanUtil { /** * 创建动态Bean * * @param propertyMap * 属性集合 * @return Object 动态生成的Bean * @throws Exception */ public static Object createBean(Map<String, Class<?>> propertyMap) throws Exception { BeanGenerator generator = new BeanGenerator(); for (String key : propertyMap.keySet()) { generator.addProperty(key, propertyMap.get(key)); } return generator.create(); } /** * 给动态Bean的属性赋值 * * @param bean * 动态Bean * @param propertyMap * 属性集合 * @throws Exception */ public static void setBeanValue(Object bean, Map<String, Object> propertyMap) throws Exception { BeanMap beanMap = BeanMap.create(bean); for (String key : propertyMap.keySet()) { beanMap.put(key, propertyMap.get(key)); } } /** * 获取动态Bean的属性值 * * @param bean * 动态Bean * @param propertyName * 属性名 * @return Object 属性值 * @throws Exception */ public static Object getBeanValue(Object bean, String propertyName) throws Exception { BeanMap beanMap = BeanMap.create(bean); PropertyDescriptor descriptor = beanMap.getPropertyDescriptor(propertyName); Method getter = descriptor.getReadMethod(); return getter.invoke(bean); } /** * 获取动态Bean的所有属性值 * * @param bean * 动态Bean * @return Map<String, Object> 属性值集合 */ public static Map<String, Object> getBeanValues(Object bean) { Map<String, Object> values = new HashMap<String, Object>(); BeanMap beanMap = BeanMap.create(bean); for (Object key : beanMap.keySet()) { values.put(key.toString(), beanMap.get(key)); } return values; } /** * 给原始对象动态添加新属性并赋值 * * @param obj * 原始对象 * @param propertyName * 新属性名 * @param value * 新属性值 * @throws Exception */ public static void addProperty(Object obj, String propertyName, Object value) throws Exception { Class<?> clazz = obj.getClass(); Field field = clazz.getDeclaredField(propertyName); field.setAccessible(true); // 获取原始对象的属性值集合 Map<String, Object> values = getBeanValues(obj); // 创建新的属性值集合,并将新属性添加到集合中 Map<String, Class<?>> propertyMap = new HashMap<String, Class<?>>(values.size() + 1); for (String key : values.keySet()) { propertyMap.put(key, values.get(key).getClass()); } propertyMap.put(propertyName, value.getClass()); // 创建新的动态Bean并赋值 Object bean = createBean(propertyMap); setBeanValue(bean, values); setBeanValue(bean, new HashMap<String, Object>() { { put(propertyName, value); } }); // 将动态Bean的属性值赋给原始对象 field.set(obj, beanMap.get(propertyName)); } } ``` 使用示例: ``` public class Person { private String name; private int age; // 省略getter和setter方法 } // 创建原始对象 Person p = new Person(); p.setName("Tom"); p.setAge(20); // 给原始对象动态添加新属性并赋值 DynamicBeanUtil.addProperty(p, "gender", "male"); // 获取新属性的值 System.out.println(p.getGender()); // 输出:male ``` 在上面的示例中,我们使用了DynamicBeanUtil工具类给原始对象Person动态添加了新属性gender,并为其赋值为male。最后,我们通过调用Person的getter方法获取到了新属性的值。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值