copyProperties(...) 在 org.springframework.beans.BeanUtils 下,在正常應用中,開發者若是須要轉換 bean,一般使用到的方法是:java
// originBean 是原型 // targetBean 是要轉換的目標 BeanUtils.copyProperties(originBean, targetBean);
在 BeanUtils 中,copyProperties 有一系列的重載方法,可是最後都會落到一個具體的實現上:spring
/** * source - origin bean * target - 目標 bean * editable - 這個 class 對象用於設置對 target 的抽象層次 * ignoreProperties - 要忽略的參數 **/ private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException { // 判空,兩個主要的 java 對象是不可爲空的 Assert.notNull(source, "Source must not be null"); Assert.notNull(target, "Target must not be null"); /** * 獲取 target 的 class 對象,若是設置了泛型,則默認使用泛型 * 若是 editable 是 null,則此處忽略 * 一般狀況下是 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; } // 此處獲取 target class 中的全部屬性的描述 PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); // 是否有須要忽略的屬性 List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null); // 此處輪詢全部的屬性 for (PropertyDescriptor targetPd : targetPds) { // 獲取寫入方法,通常來講即爲 setXX(...) Method writeMethod = targetPd.getWriteMethod(); // 確認此屬性並不被忽略,且存在寫入方法 if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null) { // 此處獲取 source 中的對應屬性的讀取方法,通常來講即爲 getXX(...) Method readMethod = sourcePd.getReadMethod(); if (readMethod != null) { // 獲取 readMethod 的返回值類型 ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod); // 獲取 writeMethod 的第一個入參類型 ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0); // 此處判斷 readMethod 的返回類型和 writeMethod 的入參類型是否爲繼承關係 // 只有當這二者爲繼承關係,或者相等的狀況下,纔會進行注入 boolean isAssignable = (sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ? ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) : targetResolvableType.isAssignableFrom(sourceResolvableType)); if (isAssignable) { 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); } } } } } } }