模擬spring框架,深入講解spring的對象的創建

導讀

項目源碼地址

因爲公司使用的是spring框架,spring是什麼?它就像包羅萬象的容器,我們什麼都可以往裏面填,比如集合持久層的hibernate或mybatis框架,類似於攔截器的的shiro框架等等。

它的好處是可以自動創建對象。以前,在沒有使用spring框架時,我們必須自己創建對象。但自從有了spring框架後,Java開發就像迎來了春天,一切都變的那麼簡單。

它有幾種自動創建對象的方式,比如構造器創建對象,set創建對象。。。如果想要對其有更多的瞭解,那麼,下載有很多博客,都對其做了詳細的介紹。我在這裏不必再做詳解了。

項目使用了logback和slf4j記錄日誌信息,因爲它們兩個是經常合作的。同時,也使用了lombok框架,這個框架可以自動生成set、get、toString、equals、hashcode方法等。

下面,便詳細介紹我的這個項目。


設計模式

本項目採用工廠和建造者設計模式。

  • 工廠設計模式用來加載配置文件。

在沒有使用註解的前提下,我們把所有的將要創建對象的信息寫進配置文件中,這就是我們常說的依賴注入。而當代碼加載時,需要加載這些配置文。

這裏需要兩個雷來支撐。一個是XmlConfigBean,記錄每個xml文件中的bean信息。XmlBeanProperty這裏記錄每個bean中的屬性信息。

加載文件方法中調用了這兩個類,當然,我是用了org下的jdom來讀取xml文件,正如以下代碼所示。

 /**
 * Created By zby on 22:57 2019/3/4
 * 加載配置文件
 *
 * @param dirPath 目錄的路徑
 */
public static LoadConfig loadXmlConFig(String dirPath) {
    if (StringUtils.isEmpty(dirPath)){
        throw new RuntimeException("路徑不存在");
    }
    if (null == config) {
        File dir = new File(dirPath);
        List<File> files = FactoryBuilder.createFileFactory().listFile(dir);
        if (CollectionUtil.isEmpty(files)) {
            throw new RuntimeException("沒有配置文件files=" + files);
        }
        allXmls = new HashMap<>();
        SAXBuilder saxBuilder = new SAXBuilder();
        Document document = null;
        for (File file : files) {
            try {
                Map<String, XmlConfigBean> beanMaps = new HashMap<>();
                //創建配置文件
                String configFileName = file.getName();
                document = saxBuilder.build(file);
                Element rootEle = document.getRootElement();
                List beans = rootEle.getChildren("bean");
                if (CollectionUtil.isNotEmpty(beans)) {
                    int i = 0;
                    for (Iterator beanIterator = beans.iterator(); beanIterator.hasNext(); i++) {
                        Element bean = (Element) beanIterator.next();
                        XmlConfigBean configBean = new XmlConfigBean();
                        configBean.setId(attributeToConfigBeanProps(file, i, bean, "id"));
                        configBean.setClazz(attributeToConfigBeanProps(file, i, bean, "class"));
                        configBean.setAutowire(attributeToConfigBeanProps(file, i, bean, "autowire"));
                        configBean.setConfigFileName(configFileName);
                        List properties = bean.getChildren();
                        Set<XmlBeanProperty> beanProperties = new LinkedHashSet<>();
                        if (CollectionUtil.isNotEmpty(properties)) {
                            int j = 0;
                            for (Iterator propertyIterator = properties.iterator(); propertyIterator.hasNext(); j++) {
                                Element property = (Element) propertyIterator.next();
                                XmlBeanProperty beanProperty = new XmlBeanProperty();
                                beanProperty.setName(attributeToBeanProperty(file, i, j, property, "name"));
                                beanProperty.setRef(attributeToBeanProperty(file, i, j, property, "ref"));
                                beanProperty.setValue(attributeToBeanProperty(file, i, j, property, "value"));
                                beanProperties.add(beanProperty);
                            }
                            configBean.setProperties(beanProperties);
                        }
                        beanMaps.put(configBean.getId(), configBean);
                    }
                }
                allXmls.put(configFileName, beanMaps);
            } catch (JDOMException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return new LoadConfig();
    }
    return config;
}

上面使用到了文件工廠設計模式,內部使用深度遞歸算法。如果初始目錄下,仍舊有子目錄,調用自身的方法,直到遇見文件,如代碼所示:

/**

  • Created By zby on 14:04 2019/2/14
  • 獲取文件的集合

*/
private void local(File dir) {

if (dir == null) {
    logger.error("文件夾爲空dir=" + dir);
    throw new RuntimeException("文件夾爲空dir=" + dir);
}
File[] fies = dir.listFiles();
if (ArrayUtil.isNotEmpty(fies)) {
    for (File fy : fies) {
        if (fy.isDirectory()) {
            local(fy);
        }
        String fileName = fy.getName();
        boolean isMatch = Pattern.compile(reg).matcher(fileName).matches();
        boolean isContains = ArrayUtil.containsAny(fileName, FilterConstants.FILE_NAMES);
        if (isMatch && !isContains) {
            fileList.add(fy);
        }
    }
}

}

  • 建造者設計模式

這裏用來修飾類信息的。比如,將類名的首字母轉化爲小寫;通過類路徑轉化爲類字面常量,如代碼所示:

 /**
 * Created By zby on 20:19 2019/2/16
 * 通過類路徑轉爲類字面常量
 *
 * @param classPath 類路徑
 */
public static <T> Class<T> classPathToClazz(String classPath) {
    if (StringUtils.isBlank(classPath)) {
        throw new RuntimeException("類路徑不存在");
    }
    try {
        return (Class<T>) Class.forName(classPath);
    } catch (ClassNotFoundException e) {
        logger.error("路徑" + classPath + "不存在,創建失敗e=" + e);
        e.printStackTrace();
    }
    return null;
}

類型轉換器

如果不是用戶自定義的類型,我們需要使用類型轉化器,將配置文件的數據轉化爲我們Javabean屬性的值。因爲,從配置文件讀取過來的值,都是字符串類型的,加入Javabean的id爲long型,因而,我們需要這個類型轉換。

/**
 * Created By zby on 22:31 2019/2/25
 * 將bean文件中的value值轉化爲屬性值
 */

public final class Transfomer {

    public final static Integer MAX_BYTE = 127;

    public final static Integer MIN_BYTE = -128;

    public final static Integer MAX_SHORT = 32767;

    public final static Integer MIN_SHORT = -32768;

    public final static String STR_TRUE = "true";

    public final static String STR_FALSE = "false";

    /**
     * Created By zby on 22:32 2019/2/25
     * 數據轉化
     *
     * @param typeName 屬性類型的名字
     * @param value    值
     */
    public static Object transformerPropertyValue(String typeName, Object value) throws IllegalAccessException {
        if (StringUtils.isBlank(typeName)) {
            throw new RuntimeException("屬性的類型不能爲空typeName+" + typeName);
        }
        if (typeName.equals(StandardBasicTypes.STRING)) {
            return objToString(value);
        } else if (typeName.equalsIgnoreCase(StandardBasicTypes.LONG)) {
            return stringToLong(objToString(value));
        } else if (typeName.equals(StandardBasicTypes.INTEGER) || typeName.equals(StandardBasicTypes.INT)) {
            return stringToInt(objToString(value));
        } else if (typeName.equalsIgnoreCase(StandardBasicTypes.BYTE)) {
            return stringToByte(objToString(value));
        } else if (typeName.equalsIgnoreCase(StandardBasicTypes.SHORT)) {
            return stringToShort(objToString(value));
        } else if (typeName.equalsIgnoreCase(StandardBasicTypes.BOOLEAN)) {
            return stringToBoolean(objToString(value));
        } else if (typeName.equalsIgnoreCase(StandardBasicTypes.DOUBLE)) {
            return stringToDouble(objToString(value));
        } else if (typeName.equalsIgnoreCase(StandardBasicTypes.FLOAT)) {
            return stringToFloat(objToString(value));
        } else if (typeName.equals(StandardBasicTypes.DATE)) {
            return stringToDate(objToString(value));
        } else if (typeName.equals(StandardBasicTypes.BIG_DECIMAL)) {
            return stringToBigDecimal(objToString(value));
        } else {
            return value;
        }
    }


    /**
     * Created By zby on 22:32 2019/2/25
     * 數據轉化
     */
    public static void transformerPropertyValue(Object currentObj, Field field, Object value) throws IllegalAccessException {
        if (null == currentObj && field == null) {
            throw new RuntimeException("當前對象或屬性爲空值");
        }
        String typeName = field.getType().getSimpleName();
        field.setAccessible(true);
        field.set(currentObj, transformerPropertyValue(typeName, value));
    }

    /**
     * Created By zby on 23:29 2019/2/25
     * obj to String
     */
    public static String objToString(Object obj) {
        return null == obj ? null : obj.toString();
    }

    /**
     * Created By zby on 23:54 2019/2/25
     * String to integer
     */
    public static Integer stringToInt(String val) {
        if (StringUtils.isBlank(val)) {
            return 0;
        }
        if (val.charAt(0) == 0) {
            throw new RuntimeException("字符串轉爲整形失敗val=" + val);
        }
        return Integer.valueOf(val);
    }

    /**
     * Created By zby on 23:31 2019/2/25
     * String to Long
     */
    public static Long stringToLong(String val) {
        return Long.valueOf(stringToInt(val));
    }

    /**
     * Created By zby on 23:52 2019/2/26
     * String to byte
     */
    public static Short stringToShort(String val) {
        Integer result = stringToInt(val);
        if (result >= MIN_SHORT && result <= MAX_SHORT) {
            return Short.valueOf(result.toString());
        }
        throw new RuntimeException("數據轉化失敗result=" + result);
    }

    /**
     * Created By zby on 0:03 2019/2/27
     * String to short
     */
    public static Byte stringToByte(String val) {
        Integer result = stringToInt(val);
        if (result >= MIN_BYTE && result <= MAX_BYTE) {
            return Byte.valueOf(result.toString());
        }
        throw new RuntimeException("數據轉化失敗result=" + result);
    }

    /**
     * Created By zby on 0:20 2019/2/27
     * string to double
     */
    public static Double stringToDouble(String val) {
        if (StringUtils.isBlank(val)) {
            throw new RuntimeException("數據爲空,轉換失敗");
        }
        return Double.valueOf(val);
    }

    /**
     * Created By zby on 0:23 2019/2/27
     * string to float
     */
    public static Float stringToFloat(String val) {
        if (StringUtils.isBlank(val)) {
            throw new RuntimeException("數據爲空,轉換失敗");
        }
        return Float.valueOf(val);
    }

    /**
     * Created By zby on 0:19 2019/2/27
     * string to boolean
     */
    public static boolean stringToBoolean(String val) {
        if (StringUtils.isBlank(val)) {
            throw new RuntimeException("數據爲空,轉換失敗val=" + val);
        }
        if (val.equals(STR_TRUE)) {
            return true;
        }
        if (val.equals(STR_FALSE)) {
            return false;
        }
        byte result = stringToByte(val);
        if (0 == result) {
            return false;
        }
        if (1 == result) {
            return true;
        }
        throw new RuntimeException("數據轉換失敗val=" + val);
    }


    /**
     * Created By zby on 0:24 2019/2/27
     * string to Date
     */
    public static Date stringToDate(String val) {
        if (StringUtils.isBlank(val)) {
            throw new RuntimeException("數據爲空,轉換失敗val=" + val);
        }
        SimpleDateFormat format = new SimpleDateFormat();
        try {
            return format.parse(val);
        } catch (ParseException e) {
            throw new RuntimeException("字符串轉爲時間失敗val=" + val);
        }
    }

    /**
     * Created By zby on 0:31 2019/2/27
     * string to big decimal
     */
    public static BigDecimal stringToBigDecimal(String val) {
        if (StringUtils.isBlank(val)) {
            throw new RuntimeException("數據爲空,轉換失敗val=" + val);
        }
        return new BigDecimal(stringToDouble(val));
    }

}

常量類型

  • 自動裝配類型
/**
 * Created By zby on 13:50 2019/2/23
 * 裝配類型
 */
public class AutowireType {
    
    /**
     * 缺省情況向,一般通過ref來自動(手動)裝配對象
     */
    public static final String NONE = null;

    /**
     * 根據屬性名事項自動裝配,
     * 如果一個bean的名稱和其他bean屬性的名稱是一樣的,將會自裝配它。
     */
    public static final String BY_NAME = "byName";

    /**
     * 根據類型來裝配
     * 如果一個bean的數據類型是用其它bean屬性的數據類型,兼容並自動裝配它。
     */
    public static final String BY_TYPE = "byType";

    /**
     * 根據構造器constructor創建對象
     */
    public static final String CONSTRUCTOR = "constructor";

    /**
     * autodetect – 如果找到默認的構造函數,使用“自動裝配用構造”; 否則,使用“按類型自動裝配”。
     */
    public static final String AUTODETECT = "autodetect";
    
}
  • 屬性類型常量池
/**
 * Created By zby on 22:44 2019/2/25
 * 類型常量池
 */
public class StandardBasicTypes {

    public static final String STRING = "String";

    public static final String LONG = "Long";

    public static final String INTEGER = "Integer";

    public static final String INT = "int";

    public static final String BYTE = "Byte";

    public static final String SHORT = "Short";

    public static final String BOOLEAN = "Boolean";

    public static final String DOUBLE = "double";

    public static final String FLOAT = "float";

    public static final String DATE = "Date";

    public static final String TIMESTAMP = "Timestamp";

    public static final String BIG_DECIMAL = "BigDecimal";

    public static final String BIG_INTEGER = "BigInteger";

}

getBean加載上下文文件

首先需要一個構造器,形參時文件的名字;getBean方法,形參是某個bean的id名字,這樣,根據當前bean的自動裝配類型,來調用響應的方法。

  /**
 * Created By zby on 11:17 2019/2/14
 * 類的上下文加載順序
 */
public class ClassPathXmlApplicationContext {

private static Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class.getName());

private String configXml;

public ClassPathXmlApplicationContext(String configXml) {
    this.configXml = configXml;
}

/**
 * Created By zby on 18:38 2019/2/24
 * bean對應的id的名稱
 */
public Object getBean(String name) {
    String dirPath="../simulaspring/src/main/resources/";
    Map<String, Map<String, XmlConfigBean>> allXmls = LoadConfig.loadXmlConFig(dirPath).getAllXmls();
    boolean contaninsKey = MapUtil.findKey(allXmls, configXml);
    if (!contaninsKey) {
        throw new RuntimeException("配置文件不存在" + configXml);
    }
    Map<String, XmlConfigBean> beans = allXmls.get(configXml);
    contaninsKey = MapUtil.findKey(beans, name);
    if (!contaninsKey) {
        throw new RuntimeException("id爲" + name + "bean不存在");
    }
    XmlConfigBean configFile = beans.get(name);
    if (null == configFile) {
        throw new RuntimeException("id爲" + name + "bean不存在");
    }
    String classPath = configFile.getClazz();
    if (StringUtils.isBlank(classPath)) {
        throw new RuntimeException("id爲" + name + "類型不存在");
    }
    String autowire = configFile.getAutowire();
    if (StringUtils.isBlank(autowire)) {
        return getBeanWithoutArgs(beans, classPath, configFile);
    } else {
        switch (autowire) {
            case AutowireType.BY_NAME:
                return getBeanByName(beans, classPath, configFile);
            case AutowireType.CONSTRUCTOR:
                return getBeanByConstruct(classPath, configFile);
            case AutowireType.AUTODETECT:
                return getByAutodetect(beans, classPath, configFile);
            case AutowireType.BY_TYPE:
                return getByType(beans, classPath, configFile);
        }
    }
    return null;
  }
}

下面主要講解默認自動裝配、屬性自動裝配、構造器自動裝配

默認自動裝配

如果我們沒有填寫自動裝配的類型,其就採用ref來自動(手動)裝配對象。

 /**
 * Created By zby on 18:33 2019/2/24
 * 在沒有設置自動裝配時,通過ref對象
 */
private Object getBeanWithoutArgs(Map<String, XmlConfigBean> beans, String classPath, XmlConfigBean configFile) {
//屬性名稱
String proName = null;
try {
    Class currentClass = Class.forName(classPath);
    //通過引用 ref 創建對象
    Set<XmlBeanProperty> properties = configFile.getProperties();
    //如果沒有屬性,就返回,便於下面的遞歸操作
    if (CollectionUtil.isEmpty(properties)) {
        return currentClass.newInstance();
    }
    Class<?> superClass = currentClass.getSuperclass();
    //TODO 父類的集合
//            List<Class> superClasses = null;
    //在創建子類構造器之前,創建父類構造器,
    // 父類構造器的參數子類構造器的參數
    Object currentObj = null;
    //當前構造器
    Object consArgsObj = null;
    String consArgsName = null;
    boolean hasSuperClass = (null != superClass && !superClass.getSimpleName().equals("Object"));
    if (hasSuperClass) {
        Constructor[] constructors = currentClass.getDeclaredConstructors();
        ArrayUtil.validateArray(superClass, constructors);
        Parameter[] parameters = constructors[0].getParameters();
        if (parameters == null || parameters.length == 0) {
            consArgsObj = constructors[0].newInstance();
        } else {
            ArrayUtil.validateArray(superClass, parameters);
            consArgsName = parameters[0].getType().getSimpleName();
            //配置文件大類型,與參數構造器的類型是否相同
            for (XmlBeanProperty property : properties) {
                String ref = property.getRef();
                if (StringUtils.isNotBlank(ref) && ref.equalsIgnoreCase(consArgsName)) {
                    classPath = beans.get(ref).getClazz();
                    Class<?> clazz = Class.forName(classPath);
                    consArgsObj = clazz.newInstance();
                }
            }
            currentObj = constructors[0].newInstance(consArgsObj);
        }
    } else {
        currentObj = currentClass.newInstance();
    }
    for (XmlBeanProperty property : properties) {
        //這裏適合用遞歸,無限調用自身
        //通過name找到屬性,配置文件中是否有該屬性,通過ref找到其對應的bean文件
        proName = property.getName();
        Field field = currentClass.getDeclaredField(proName);
        if (null != field) {
            String ref = property.getRef();
            Object value = property.getValue();
            //如果沒有賦初值,就通過類型創建
            if (null == value && StringUtils.isNotBlank(ref)) {
                boolean flag = StringUtils.isNotBlank(consArgsName) && null != consArgsObj && consArgsName.equalsIgnoreCase(ref);
                //遞歸調用獲取屬性對象
                value = flag ? consArgsObj : getBean(ref);
            }
            field.setAccessible(true);
            Transfomer.transformerPropertyValue(currentObj, field, value);
        }
    }
    return currentObj;
} catch (ClassNotFoundException e) {
    logger.error("名爲" + classPath + "類不存在");
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
} catch (NoSuchFieldException e) {
    logger.error(classPath + "類的屬性" + proName + "不存在");
    throw new RuntimeException(classPath + "類的屬性" + proName + "不存在");
}
return null;
}

構造器創建對象

根據構造器constructor創建對象

/**
 * Created By zby on 23:06 2019/3/2
 *
 * @param classPath  類路徑
 * @param configFile 配置文件
 */
private Object getBeanByConstruct(String classPath, XmlConfigBean configFile) {
    try {
        Class currentClass = Class.forName(classPath);
        Set<XmlBeanProperty> properties = configFile.getProperties();
        if (CollectionUtil.isEmpty(properties)) {
            return currentClass.newInstance();
        }
        ///構造器參數類型和構造器對象集合
        Object[] objects = new Object[properties.size()];
        Class<?>[] paramType = new Class[properties.size()];
        Field[] fields = currentClass.getDeclaredFields();
        int i = 0;
        for (Iterator iterator = properties.iterator(); iterator.hasNext(); i++) {
            XmlBeanProperty property = (XmlBeanProperty) iterator.next();
            String proName = property.getName();
            String ref = property.getRef();
            Object value = property.getValue();
            for (Field field : fields) {
                Class<?> type = field.getType();
                String typeName = type.getSimpleName();
                String paramName = field.getName();
                if (paramName.equals(proName) && ObjectUtil.isNotNull(value) && StringUtils.isBlank(ref)) {
                    objects[i] = Transfomer.transformerPropertyValue(typeName, value);
                    paramType[i] = type;
                    break;
                } else if (paramName.equals(proName) && StringUtils.isNotBlank(ref) && ObjectUtil.isNull(value)) {
                    objects[i] = getBean(ref);
                    paramType[i] = type;
                    break;
                }
            }
        }
        return currentClass.getConstructor(paramType).newInstance(objects);
    } catch (ClassNotFoundException e) {
        logger.error("名爲" + classPath + "類不存在");
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    return null;
}

屬性自動裝配

根據屬性名事項自動裝配,如果一個bean的名稱和其他bean屬性的名稱是一樣的,將會自裝配它。

 /**
 * Created By zby on 21:16 2019/3/1
 * 根據屬性名事項自動裝配,
 * @param classPath 類路徑
 * @param configFile  配置文件
 */
private Object getBeanByName( String classPath, XmlConfigBean configFile) {
    String proName = null;
    try {
        Class currentClass = Class.forName(classPath);
        Class superclass = currentClass.getSuperclass();
        Method[] methods = currentClass.getDeclaredMethods();
        List<Method> methodList = MethodHelper.filterSetMethods(methods);
        Object currentObj = currentClass.newInstance();
        Set<XmlBeanProperty> properties = configFile.getProperties();
        //配置文件中,但是有父類,
        if (CollectionUtil.isEmpty(properties)) {
            boolean isExit = null != superclass && !superclass.getSimpleName().equals("Object");
            if (isExit) {
                Field[] parentFields = superclass.getDeclaredFields();
                if (ArrayUtil.isNotEmpty(parentFields)) {
                    if (CollectionUtil.isNotEmpty(methodList)) {
                        for (Field parentField : parentFields) {
                            for (Method method : methodList) {
                                if (MethodHelper.methodNameToProName(method.getName()).equals(parentField.getName())) {
                                    //如果有泛型的話
                                    Type genericType = currentClass.getGenericSuperclass();
                                    if (null != genericType) {
                                        String genericName = genericType.getTypeName();
                                        genericName = StringUtils.substring(genericName, genericName.indexOf("<") + 1, genericName.indexOf(">"));
                                        Class genericClass = Class.forName(genericName);
                                        method.setAccessible(true);
                                        method.invoke(currentObj, genericClass);
                                    }
                                    break;
                                }
                            }
                            break;
                        }
                    }
                }

            }
            return currentObj;
        }
        //傳遞給父級對象 service -- 》value
        List<Method> tmpList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        Object value = null;
        for (XmlBeanProperty property : properties) {
            proName = property.getName();
            if (ArrayUtil.isNotEmpty(methods)) {
                String ref = property.getRef();
                value = property.getValue();
                for (Method method : methodList) {
                    String methodName = MethodHelper.methodNameToProName(method.getName());
                    Field field = currentClass.getDeclaredField(methodName);
                    if (methodName.equals(proName) && null != field) {
                        if (null == value && StringUtils.isNotBlank(ref)) {
                            value = getBean(ref);
                        } else if (value != null && StringUtils.isBlank(ref)) {
                            value = Transfomer.transformerPropertyValue(field.getType().getSimpleName(), value);
                        }
                        method.setAccessible(true);
                        method.invoke(currentObj, value);
                        map.put(proName, value);
                        tmpList.add(method);
                        break;
                    }
                }
            }
        }
        tmpList = MethodHelper.removeMethod(methodList, tmpList);
        for (Method method : tmpList) {
            Class<?>[] type = method.getParameterTypes();
            if (ArrayUtil.isEmpty(type)) {
                throw new RuntimeException("傳遞給父級對象的參數爲空type=" + type);
            }
            for (Class<?> aClass : type) {
                String superName = ClassHelper.classNameToProName(aClass.getSimpleName());
                value = map.get(superName);
                method.setAccessible(true);
                method.invoke(currentObj, value);
            }
        }
        return currentObj;
    } catch (ClassNotFoundException e) {
        logger.error("名爲" + classPath + "類不存在");
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        logger.error("類" + classPath + "屬性" + proName + "不存在");
        e.printStackTrace();
    }
    return null;
}

總結

這裏沒有使用註解,我們可以使用註解的方式實現自動裝配,但這不spring的核心,應該時spring的美化,核心值如何實現自動裝配。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章