!1335 优化BeanUtil.copyToList拷贝较大数据量的性能问题

Merge pull request !1335 from IzayoiYurin/v5-dev
This commit is contained in:
Looly 2025-04-26 05:17:24 +00:00 committed by Gitee
commit 3ff79b3f23
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
4 changed files with 75 additions and 5 deletions

View File

@ -181,7 +181,8 @@ public class BeanDesc implements Serializable {
prop.setter = propIgnoreCase.setter; prop.setter = propIgnoreCase.setter;
} }
} }
// 所有属性完成填充后的初始化逻辑
prop.initialize();
return prop; return prop;
} }

View File

@ -36,6 +36,22 @@ public class PropDesc {
* Setter方法 * Setter方法
*/ */
protected Method setter; protected Method setter;
/**
* get方法或字段上有无transient关键字和@Transient注解
*/
private boolean transientForGet;
/**
* set方法或字段上有无transient关键字和@Transient注解
*/
private boolean transientForSet;
/**
* 检查set方法和字段有无@PropIgnore注解
*/
private boolean ignoreGet;
/**
* 检查set方法和字段有无@PropIgnore注解
*/
private boolean ignoreSet;
/** /**
* 构造<br> * 构造<br>
@ -51,6 +67,17 @@ public class PropDesc {
this.setter = ClassUtil.setAccessible(setter); this.setter = ClassUtil.setAccessible(setter);
} }
/**
* 在对象的所有属性设置完成后执行初始化逻辑
* <p>
* 预先计算transient关键字和@Transient注解{@link PropIgnore}注解信息
*/
public void initialize() {
transientForGet = isTransientForGet();
transientForSet = isTransientForSet();
ignoreGet = isIgnoreGet();
ignoreSet = isIgnoreSet();
}
/** /**
* 获取字段名如果存在Alias注解读取注解的值作为名称 * 获取字段名如果存在Alias注解读取注解的值作为名称
* *
@ -137,12 +164,12 @@ public class PropDesc {
} }
// 检查transient关键字和@Transient注解 // 检查transient关键字和@Transient注解
if (checkTransient && isTransientForGet()) { if (checkTransient && transientForGet) {
return false; return false;
} }
// 检查@PropIgnore注解 // 检查@PropIgnore注解
return false == isIgnoreGet(); return false == ignoreGet;
} }
/** /**
@ -207,12 +234,12 @@ public class PropDesc {
} }
// 检查transient关键字和@Transient注解 // 检查transient关键字和@Transient注解
if (checkTransient && isTransientForSet()) { if (checkTransient && transientForSet) {
return false; return false;
} }
// 检查@PropIgnore注解 // 检查@PropIgnore注解
return false == isIgnoreSet(); return false == ignoreSet;
} }
/** /**

View File

@ -9,6 +9,7 @@ import cn.hutool.core.lang.Editor;
import cn.hutool.core.lang.func.Func1; import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.lang.func.LambdaUtil; import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@ -91,6 +92,14 @@ public class CopyOptions implements Serializable {
return null; return null;
} }
// 快速处理简单值类型的转换
if (type instanceof Class){
Class<?> targetType = (Class<?>) type;
if (ClassUtil.isSimpleValueType(targetType) && targetType.isInstance(value)) {
return targetType.cast(value);
}
}
if (value instanceof IJSONTypeConverter) { if (value instanceof IJSONTypeConverter) {
return ((IJSONTypeConverter) value).toBean(ObjectUtil.defaultIfNull(type, Object.class)); return ((IJSONTypeConverter) value).toBean(ObjectUtil.defaultIfNull(type, Object.class));
} }

View File

@ -5,6 +5,8 @@ import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.bean.copier.ValueProvider; import cn.hutool.core.bean.copier.ValueProvider;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
import cn.hutool.core.map.MapBuilder; import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
@ -707,6 +709,37 @@ public class BeanUtilTest {
} }
@Test
public void copyLargeListTest(){
final SubPerson person = new SubPerson();
person.setName("测试A11");
person.setAge(14);
person.setOpenid("11213232");
person.setId(UUID.randomUUID());
person.setSubName("sub名字");
person.setSlow(true);
person.setDate(LocalDateTime.now());
person.setDate2(LocalDate.now());
final List<SubPerson> list = new ArrayList<>();
CollUtil.padRight(list, 1000, person);
// 预先构建一次缓存防止干扰
BeanUtil.copyProperties(person, new SubPerson2());
// org.springframework.beans.BeanUtils.copyProperties(new SubPerson(), new SubPerson2());
Console.log("copy bean size: {}\n", list.size());
final StopWatch stopWatch = new StopWatch();
stopWatch.start("BeanUtil#copyToList");
List<SubPerson2> copyList = BeanUtil.copyToList(list, SubPerson2.class);
// list.forEach(item -> org.springframework.beans.BeanUtils.copyProperties(item, new SubPerson2()));
stopWatch.stop();
Console.log(stopWatch.prettyPrint());
assertEquals(copyList.size(),list.size());
}
@Test @Test
public void toMapTest() { public void toMapTest() {
// 测试转map的时候返回key // 测试转map的时候返回key