以前一直以为BeanUtils使用的反射,今天看了一下源码,才发现用的是内省,mark一下
关于内省的介绍: https://blog.csdn.net/weixin_42069143/article/details/8211972
Demo代码:
@Test
public void beanUtilsCopy(){
BeanWrapperPojo beanWrapperPojo = new BeanWrapperPojo();
beanWrapperPojo.setAge(12);
beanWrapperPojo.setName("Fev");
BeanWrapperPojo beanWrapperPojo1 = new BeanWrapperPojo();
BeanUtils.copyProperties(beanWrapperPojo,beanWrapperPojo1);
}
进入源码:
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties)
此处有四个参数 :
source:即源对象。
target: 目标对象。
editable: 用于验证目标对象是不是editable类型的。
ignoreProperties: 需要忽视的对象。
具体源码:
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;
PropertyDescriptor[] var7 = targetPds;
int var8 = targetPds.length;
for(int var9 = 0; var9 < var8; ++var9) {
PropertyDescriptor targetPd = var7[var9];
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 var15) {
throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);
}
}
}
}
}
过程:
1、如果 参数editable不为空,则判断target是不是editable的实例。
2、 之后获取目标类target的PropertyDescriptor[]
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
方法getPropertyDescriptors(actualEditable);这里是获取PropertyDescriptor的操作并将其放入缓存中,为了防止并发,是通过actualEditable与其对应的PropertyDescriptor[]放在ConcurrentReferenceHashMap中。
3、之后则是循环PropertyDescriptor[],如果PropertyDescriptor在ignoreProperties中则跳过,如果不在,则进行赋值:
首先通过目标对象的生效名称获取对应源对象的PropertyDescriptor :
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
之后通过目标对象PropertyDescriptor 的getWriteMethod()方法以及源对象PropertyDescriptor的getReadMethod进行值的读取与赋值。