模拟spring框架,深入讲解spring的对象的创建

系统管理员 2022-12-07 01:25 197阅读 0赞

目录

  • 导读
  • 设计思想
  • 设计模式
    • 工厂设计模式用来加载配置文件。
    • 建造者设计模式
  • 类型转换器
  • 常量类型
    • 自动装配类型
    • 属性类型常量池
  • getBean加载上下文文件
    • 默认自动装配
    • 构造器创建对象
    • 属性自动装配
  • 总结

导读

这是我思否上的一篇文章,特地拿过来放到csdn上:https://segmentfault.com/a/1190000018536099

项目源码地址

因为公司使用的是spring框架,spring是什么?它就像包罗万象的容器,我们什么都可以往里面填,比如集合持久层的hibernate或mybatis框架,类似于拦截器的的shiro框架等等。

它的好处是可以自动创建对象。以前,在没有使用spring框架时,我们必须自己创建对象。但自从有了spring框架后,Java开发就像迎来了春天,一切都变的那么简单。

它有几种自动创建对象的方式,比如构造器创建对象,set创建对象。。。如果想要对其有更多的了解,那么,现在有很多博客,都对其做了详细的介绍。我在这里不必再做详解了。

本项目使用了logback和slf4j记录日志信息,因为它们两个是经常合作的。同时,也使用了lombok框架,这个框架可以自动生成set、get、toString、equals、hashcode方法等。

下面,便详细介绍我的这个项目。


设计思想

工欲善其事,必先利其器。在设计框架之前,一定要清楚在写当前框架可能会面临的问题

  1. 加载和读取配置文件
  2. 解析配置文件,创建一个实体类XmlConfigBean ,记录每个bean的信息,包括id,class,属性等。
  3. 创建XmlBeanProperty,记录每个bean的属性集合,并注入到当前XmlConfigBean的实例化对象中。
  4. 通过反射实例化XmlConfigBean中的类对象。

设计模式

本项目采用工厂和建造者设计模式。

工厂设计模式用来加载配置文件。

在没有使用注解的前提下,我们把所有的将要创建对象的信息写进配置文件中,这就是我们常说的依赖注入。而当代码加载时,需要加载这些配置文件。

这里需要两个类来支撑。一个是XmlConfigBean,记录每个xml文件中的bean信息。XmlBeanProperty这里记录每个bean中的属性信息。

加载文件方法中调用了这两个类,当然,我是用了org下的jdom来读取xml文件,正如以下代码所示。

  1. /**
  2. * Created By zby on 22:57 2019/3/4
  3. * 加载配置文件
  4. *
  5. * @param dirPath 目录的路径
  6. */
  7. public static LoadConfig loadXmlConFig(String dirPath) {
  8. if (StringUtils.isEmpty(dirPath)){
  9. throw new RuntimeException("路径不存在");
  10. }
  11. if (null == config) {
  12. File dir = new File(dirPath);
  13. List<File> files = FactoryBuilder.createFileFactory().listFile(dir);
  14. if (CollectionUtil.isEmpty(files)) {
  15. throw new RuntimeException("没有配置文件files=" + files);
  16. }
  17. allXmls = new HashMap<>();
  18. SAXBuilder saxBuilder = new SAXBuilder();
  19. Document document = null;
  20. for (File file : files) {
  21. try {
  22. Map<String, XmlConfigBean> beanMaps = new HashMap<>();
  23. //创建配置文件
  24. String configFileName = file.getName();
  25. document = saxBuilder.build(file);
  26. Element rootEle = document.getRootElement();
  27. List beans = rootEle.getChildren("bean");
  28. if (CollectionUtil.isNotEmpty(beans)) {
  29. int i = 0;
  30. for (Iterator beanIterator = beans.iterator(); beanIterator.hasNext(); i++) {
  31. Element bean = (Element) beanIterator.next();
  32. XmlConfigBean configBean = new XmlConfigBean();
  33. configBean.setId(attributeToConfigBeanProps(file, i, bean, "id"));
  34. configBean.setClazz(attributeToConfigBeanProps(file, i, bean, "class"));
  35. configBean.setAutowire(attributeToConfigBeanProps(file, i, bean, "autowire"));
  36. configBean.setConfigFileName(configFileName);
  37. List properties = bean.getChildren();
  38. Set<XmlBeanProperty> beanProperties = new LinkedHashSet<>();
  39. if (CollectionUtil.isNotEmpty(properties)) {
  40. int j = 0;
  41. for (Iterator propertyIterator = properties.iterator(); propertyIterator.hasNext(); j++) {
  42. Element property = (Element) propertyIterator.next();
  43. XmlBeanProperty beanProperty = new XmlBeanProperty();
  44. beanProperty.setName(attributeToBeanProperty(file, i, j, property, "name"));
  45. beanProperty.setRef(attributeToBeanProperty(file, i, j, property, "ref"));
  46. beanProperty.setValue(attributeToBeanProperty(file, i, j, property, "value"));
  47. beanProperties.add(beanProperty);
  48. }
  49. configBean.setProperties(beanProperties);
  50. }
  51. beanMaps.put(configBean.getId(), configBean);
  52. }
  53. }
  54. allXmls.put(configFileName, beanMaps);
  55. } catch (JDOMException e) {
  56. e.printStackTrace();
  57. } catch (IOException e) {
  58. e.printStackTrace();
  59. }
  60. }
  61. return new LoadConfig();
  62. }
  63. return config;
  64. }

上面使用到了文件工厂设计模式,内部使用深度递归算法。如果初始目录下,仍旧有子目录,调用自身的方法,直到遇见文件,如代码所示:

  1. /**
  2. * Created By zby on 14:04 2019/2/14
  3. * 获取文件的集合
  4. */
  5. private void local(File dir) {
  6. if (dir == null) {
  7. logger.error("文件夹为空dir=" + dir);
  8. throw new RuntimeException("文件夹为空dir=" + dir);
  9. }
  10. File[] fies = dir.listFiles();
  11. if (ArrayUtil.isNotEmpty(fies)) {
  12. for (File fy : fies) {
  13. if (fy.isDirectory()) {
  14. local(fy);
  15. }
  16. String fileName = fy.getName();
  17. boolean isMatch = Pattern.compile(reg).matcher(fileName).matches();
  18. boolean isContains = ArrayUtil.containsAny(fileName, FilterConstants.FILE_NAMES);
  19. if (isMatch && !isContains) {
  20. fileList.add(fy);
  21. }
  22. }
  23. }
  24. }

建造者设计模式

这里用来修饰类信息的。比如,将类名的首字母转化为小写;通过类路径转化为类字面常量,如代码所示:

  1. /**
  2. * Created By zby on 20:19 2019/2/16
  3. * 通过类路径转为类字面常量
  4. *
  5. * @param classPath 类路径
  6. */
  7. public static <T> Class<T> classPathToClazz(String classPath) {
  8. if (StringUtils.isBlank(classPath)) {
  9. throw new RuntimeException("类路径不存在");
  10. }
  11. try {
  12. return (Class<T>) Class.forName(classPath);
  13. } catch (ClassNotFoundException e) {
  14. logger.error("路径" + classPath + "不存在,创建失败e=" + e);
  15. e.printStackTrace();
  16. }
  17. return null;
  18. }

类型转换器

如果不是用户自定义的类型,我们需要使用类型转化器,将配置文件的数据转化为我们Javabean属性的值。因为,从配置文件读取过来的值,都是字符串类型的,加入Javabean的id为long型,因而,我们需要这个类型转换。

  1. /**
  2. * Created By zby on 22:31 2019/2/25
  3. * 将bean文件中的value值转化为属性值
  4. */
  5. public final class Transfomer {
  6. public final static Integer MAX_BYTE = 127;
  7. public final static Integer MIN_BYTE = -128;
  8. public final static Integer MAX_SHORT = 32767;
  9. public final static Integer MIN_SHORT = -32768;
  10. public final static String STR_TRUE = "true";
  11. public final static String STR_FALSE = "false";
  12. /**
  13. * Created By zby on 22:32 2019/2/25
  14. * 数据转化
  15. *
  16. * @param typeName 属性类型的名字
  17. * @param value 值
  18. */
  19. public static Object transformerPropertyValue(String typeName, Object value) throws IllegalAccessException {
  20. if (StringUtils.isBlank(typeName)) {
  21. throw new RuntimeException("属性的类型不能为空typeName+" + typeName);
  22. }
  23. if (typeName.equals(StandardBasicTypes.STRING)) {
  24. return objToString(value);
  25. } else if (typeName.equalsIgnoreCase(StandardBasicTypes.LONG)) {
  26. return stringToLong(objToString(value));
  27. } else if (typeName.equals(StandardBasicTypes.INTEGER) || typeName.equals(StandardBasicTypes.INT)) {
  28. return stringToInt(objToString(value));
  29. } else if (typeName.equalsIgnoreCase(StandardBasicTypes.BYTE)) {
  30. return stringToByte(objToString(value));
  31. } else if (typeName.equalsIgnoreCase(StandardBasicTypes.SHORT)) {
  32. return stringToShort(objToString(value));
  33. } else if (typeName.equalsIgnoreCase(StandardBasicTypes.BOOLEAN)) {
  34. return stringToBoolean(objToString(value));
  35. } else if (typeName.equalsIgnoreCase(StandardBasicTypes.DOUBLE)) {
  36. return stringToDouble(objToString(value));
  37. } else if (typeName.equalsIgnoreCase(StandardBasicTypes.FLOAT)) {
  38. return stringToFloat(objToString(value));
  39. } else if (typeName.equals(StandardBasicTypes.DATE)) {
  40. return stringToDate(objToString(value));
  41. } else if (typeName.equals(StandardBasicTypes.BIG_DECIMAL)) {
  42. return stringToBigDecimal(objToString(value));
  43. } else {
  44. return value;
  45. }
  46. }
  47. /**
  48. * Created By zby on 22:32 2019/2/25
  49. * 数据转化
  50. */
  51. public static void transformerPropertyValue(Object currentObj, Field field, Object value) throws IllegalAccessException {
  52. if (null == currentObj && field == null) {
  53. throw new RuntimeException("当前对象或属性为空值");
  54. }
  55. String typeName = field.getType().getSimpleName();
  56. field.setAccessible(true);
  57. field.set(currentObj, transformerPropertyValue(typeName, value));
  58. }
  59. /**
  60. * Created By zby on 23:29 2019/2/25
  61. * obj to String
  62. */
  63. public static String objToString(Object obj) {
  64. return null == obj ? null : obj.toString();
  65. }
  66. /**
  67. * Created By zby on 23:54 2019/2/25
  68. * String to integer
  69. */
  70. public static Integer stringToInt(String val) {
  71. if (StringUtils.isBlank(val)) {
  72. return 0;
  73. }
  74. if (val.charAt(0) == 0) {
  75. throw new RuntimeException("字符串转为整形失败val=" + val);
  76. }
  77. return Integer.valueOf(val);
  78. }
  79. /**
  80. * Created By zby on 23:31 2019/2/25
  81. * String to Long
  82. */
  83. public static Long stringToLong(String val) {
  84. return Long.valueOf(stringToInt(val));
  85. }
  86. /**
  87. * Created By zby on 23:52 2019/2/26
  88. * String to byte
  89. */
  90. public static Short stringToShort(String val) {
  91. Integer result = stringToInt(val);
  92. if (result >= MIN_SHORT && result <= MAX_SHORT) {
  93. return Short.valueOf(result.toString());
  94. }
  95. throw new RuntimeException("数据转化失败result=" + result);
  96. }
  97. /**
  98. * Created By zby on 0:03 2019/2/27
  99. * String to short
  100. */
  101. public static Byte stringToByte(String val) {
  102. Integer result = stringToInt(val);
  103. if (result >= MIN_BYTE && result <= MAX_BYTE) {
  104. return Byte.valueOf(result.toString());
  105. }
  106. throw new RuntimeException("数据转化失败result=" + result);
  107. }
  108. /**
  109. * Created By zby on 0:20 2019/2/27
  110. * string to double
  111. */
  112. public static Double stringToDouble(String val) {
  113. if (StringUtils.isBlank(val)) {
  114. throw new RuntimeException("数据为空,转换失败");
  115. }
  116. return Double.valueOf(val);
  117. }
  118. /**
  119. * Created By zby on 0:23 2019/2/27
  120. * string to float
  121. */
  122. public static Float stringToFloat(String val) {
  123. if (StringUtils.isBlank(val)) {
  124. throw new RuntimeException("数据为空,转换失败");
  125. }
  126. return Float.valueOf(val);
  127. }
  128. /**
  129. * Created By zby on 0:19 2019/2/27
  130. * string to boolean
  131. */
  132. public static boolean stringToBoolean(String val) {
  133. if (StringUtils.isBlank(val)) {
  134. throw new RuntimeException("数据为空,转换失败val=" + val);
  135. }
  136. if (val.equals(STR_TRUE)) {
  137. return true;
  138. }
  139. if (val.equals(STR_FALSE)) {
  140. return false;
  141. }
  142. byte result = stringToByte(val);
  143. if (0 == result) {
  144. return false;
  145. }
  146. if (1 == result) {
  147. return true;
  148. }
  149. throw new RuntimeException("数据转换失败val=" + val);
  150. }
  151. /**
  152. * Created By zby on 0:24 2019/2/27
  153. * string to Date
  154. */
  155. public static Date stringToDate(String val) {
  156. if (StringUtils.isBlank(val)) {
  157. throw new RuntimeException("数据为空,转换失败val=" + val);
  158. }
  159. SimpleDateFormat format = new SimpleDateFormat();
  160. try {
  161. return format.parse(val);
  162. } catch (ParseException e) {
  163. throw new RuntimeException("字符串转为时间失败val=" + val);
  164. }
  165. }
  166. /**
  167. * Created By zby on 0:31 2019/2/27
  168. * string to big decimal
  169. */
  170. public static BigDecimal stringToBigDecimal(String val) {
  171. if (StringUtils.isBlank(val)) {
  172. throw new RuntimeException("数据为空,转换失败val=" + val);
  173. }
  174. return new BigDecimal(stringToDouble(val));
  175. }
  176. }

常量类型

自动装配类型

  1. /**
  2. * Created By zby on 13:50 2019/2/23
  3. * 装配类型
  4. */
  5. public class AutowireType {
  6. /**
  7. * 缺省情况向,一般通过ref来自动(手动)装配对象
  8. */
  9. public static final String NONE = null;
  10. /**
  11. * 根据属性名事项自动装配,
  12. * 如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。
  13. */
  14. public static final String BY_NAME = "byName";
  15. /**
  16. * 根据类型来装配
  17. * 如果一个bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它。
  18. */
  19. public static final String BY_TYPE = "byType";
  20. /**
  21. * 根据构造器constructor创建对象
  22. */
  23. public static final String CONSTRUCTOR = "constructor";
  24. /**
  25. * autodetect – 如果找到默认的构造函数,使用“自动装配用构造”; 否则,使用“按类型自动装配”。
  26. */
  27. public static final String AUTODETECT = "autodetect";
  28. }

属性类型常量池

  1. /**
  2. * Created By zby on 22:44 2019/2/25
  3. * 类型常量池
  4. */
  5. public class StandardBasicTypes {
  6. public static final String STRING = "String";
  7. public static final String LONG = "Long";
  8. public static final String INTEGER = "Integer";
  9. public static final String INT = "int";
  10. public static final String BYTE = "Byte";
  11. public static final String SHORT = "Short";
  12. public static final String BOOLEAN = "Boolean";
  13. public static final String DOUBLE = "double";
  14. public static final String FLOAT = "float";
  15. public static final String DATE = "Date";
  16. public static final String TIMESTAMP = "Timestamp";
  17. public static final String BIG_DECIMAL = "BigDecimal";
  18. public static final String BIG_INTEGER = "BigInteger";
  19. }

getBean加载上下文文件

首先需要一个构造器,形参时文件的名字;getBean方法,形参是某个bean的id名字,这样,根据当前bean的自动装配类型,来调用相关的方法。

  1. /**
  2. * Created By zby on 11:17 2019/2/14
  3. * 类的上下文加载顺序
  4. */
  5. public class ClassPathXmlApplicationContext {
  6. private static Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class.getName());
  7. private String configXml;
  8. public ClassPathXmlApplicationContext(String configXml) {
  9. this.configXml = configXml;
  10. }
  11. /**
  12. * Created By zby on 18:38 2019/2/24
  13. * bean对应的id的名称
  14. */
  15. public Object getBean(String name) {
  16. String dirPath="../simulaspring/src/main/resources/";
  17. Map<String, Map<String, XmlConfigBean>> allXmls = LoadConfig.loadXmlConFig(dirPath).getAllXmls();
  18. boolean contaninsKey = MapUtil.findKey(allXmls, configXml);
  19. if (!contaninsKey) {
  20. throw new RuntimeException("配置文件不存在" + configXml);
  21. }
  22. Map<String, XmlConfigBean> beans = allXmls.get(configXml);
  23. contaninsKey = MapUtil.findKey(beans, name);
  24. if (!contaninsKey) {
  25. throw new RuntimeException("id为" + name + "bean不存在");
  26. }
  27. XmlConfigBean configFile = beans.get(name);
  28. if (null == configFile) {
  29. throw new RuntimeException("id为" + name + "bean不存在");
  30. }
  31. String classPath = configFile.getClazz();
  32. if (StringUtils.isBlank(classPath)) {
  33. throw new RuntimeException("id为" + name + "类型不存在");
  34. }
  35. String autowire = configFile.getAutowire();
  36. if (StringUtils.isBlank(autowire)) {
  37. return getBeanWithoutArgs(beans, classPath, configFile);
  38. } else {
  39. switch (autowire) {
  40. case AutowireType.BY_NAME:
  41. return getBeanByName(beans, classPath, configFile);
  42. case AutowireType.CONSTRUCTOR:
  43. return getBeanByConstruct(classPath, configFile);
  44. case AutowireType.AUTODETECT:
  45. return getByAutodetect(beans, classPath, configFile);
  46. case AutowireType.BY_TYPE:
  47. return getByType(beans, classPath, configFile);
  48. }
  49. }
  50. return null;
  51. }
  52. }

下面主要讲解默认自动装配、属性自动装配、构造器自动装配


默认自动装配

如果我们没有填写自动装配的类型,其就采用ref来自动(手动)装配对象。

  1. /**
  2. * Created By zby on 18:33 2019/2/24
  3. * 在没有设置自动装配时,通过ref对象
  4. */
  5. private Object getBeanWithoutArgs(Map<String, XmlConfigBean> beans, String classPath, XmlConfigBean configFile) {
  6. //属性名称
  7. String proName = null;
  8. try {
  9. Class currentClass = Class.forName(classPath);
  10. //通过引用 ref 创建对象
  11. Set<XmlBeanProperty> properties = configFile.getProperties();
  12. //如果没有属性,就返回,便于下面的递归操作
  13. if (CollectionUtil.isEmpty(properties)) {
  14. return currentClass.newInstance();
  15. }
  16. Class<?> superClass = currentClass.getSuperclass();
  17. //TODO 父类的集合
  18. // List<Class> superClasses = null;
  19. //在创建子类构造器之前,创建父类构造器,
  20. // 父类构造器的参数子类构造器的参数
  21. Object currentObj = null;
  22. //当前构造器
  23. Object consArgsObj = null;
  24. String consArgsName = null;
  25. boolean hasSuperClass = (null != superClass && !superClass.getSimpleName().equals("Object"));
  26. if (hasSuperClass) {
  27. Constructor[] constructors = currentClass.getDeclaredConstructors();
  28. ArrayUtil.validateArray(superClass, constructors);
  29. Parameter[] parameters = constructors[0].getParameters();
  30. if (parameters == null || parameters.length == 0) {
  31. consArgsObj = constructors[0].newInstance();
  32. } else {
  33. ArrayUtil.validateArray(superClass, parameters);
  34. consArgsName = parameters[0].getType().getSimpleName();
  35. //配置文件大类型,与参数构造器的类型是否相同
  36. for (XmlBeanProperty property : properties) {
  37. String ref = property.getRef();
  38. if (StringUtils.isNotBlank(ref) && ref.equalsIgnoreCase(consArgsName)) {
  39. classPath = beans.get(ref).getClazz();
  40. Class<?> clazz = Class.forName(classPath);
  41. consArgsObj = clazz.newInstance();
  42. }
  43. }
  44. currentObj = constructors[0].newInstance(consArgsObj);
  45. }
  46. } else {
  47. currentObj = currentClass.newInstance();
  48. }
  49. for (XmlBeanProperty property : properties) {
  50. //这里适合用递归,无限调用自身
  51. //通过name找到属性,配置文件中是否有该属性,通过ref找到其对应的bean文件
  52. proName = property.getName();
  53. Field field = currentClass.getDeclaredField(proName);
  54. if (null != field) {
  55. String ref = property.getRef();
  56. Object value = property.getValue();
  57. //如果没有赋初值,就通过类型创建
  58. if (null == value && StringUtils.isNotBlank(ref)) {
  59. boolean flag = StringUtils.isNotBlank(consArgsName) && null != consArgsObj && consArgsName.equalsIgnoreCase(ref);
  60. //递归调用获取属性对象
  61. value = flag ? consArgsObj : getBean(ref);
  62. }
  63. field.setAccessible(true);
  64. Transfomer.transformerPropertyValue(currentObj, field, value);
  65. }
  66. }
  67. return currentObj;
  68. } catch (ClassNotFoundException e) {
  69. logger.error("名为" + classPath + "类不存在");
  70. e.printStackTrace();
  71. } catch (InstantiationException e) {
  72. e.printStackTrace();
  73. } catch (IllegalAccessException e) {
  74. e.printStackTrace();
  75. } catch (InvocationTargetException e) {
  76. e.printStackTrace();
  77. } catch (NoSuchFieldException e) {
  78. logger.error(classPath + "类的属性" + proName + "不存在");
  79. throw new RuntimeException(classPath + "类的属性" + proName + "不存在");
  80. }
  81. return null;
  82. }

构造器创建对象

根据构造器constructor创建对象

  1. /**
  2. * Created By zby on 23:06 2019/3/2
  3. *
  4. * @param classPath 类路径
  5. * @param configFile 配置文件
  6. */
  7. private Object getBeanByConstruct(String classPath, XmlConfigBean configFile) {
  8. try {
  9. Class currentClass = Class.forName(classPath);
  10. Set<XmlBeanProperty> properties = configFile.getProperties();
  11. if (CollectionUtil.isEmpty(properties)) {
  12. return currentClass.newInstance();
  13. }
  14. ///构造器参数类型和构造器对象集合
  15. Object[] objects = new Object[properties.size()];
  16. Class<?>[] paramType = new Class[properties.size()];
  17. Field[] fields = currentClass.getDeclaredFields();
  18. int i = 0;
  19. for (Iterator iterator = properties.iterator(); iterator.hasNext(); i++) {
  20. XmlBeanProperty property = (XmlBeanProperty) iterator.next();
  21. String proName = property.getName();
  22. String ref = property.getRef();
  23. Object value = property.getValue();
  24. for (Field field : fields) {
  25. Class<?> type = field.getType();
  26. String typeName = type.getSimpleName();
  27. String paramName = field.getName();
  28. if (paramName.equals(proName) && ObjectUtil.isNotNull(value) && StringUtils.isBlank(ref)) {
  29. objects[i] = Transfomer.transformerPropertyValue(typeName, value);
  30. paramType[i] = type;
  31. break;
  32. } else if (paramName.equals(proName) && StringUtils.isNotBlank(ref) && ObjectUtil.isNull(value)) {
  33. objects[i] = getBean(ref);
  34. paramType[i] = type;
  35. break;
  36. }
  37. }
  38. }
  39. return currentClass.getConstructor(paramType).newInstance(objects);
  40. } catch (ClassNotFoundException e) {
  41. logger.error("名为" + classPath + "类不存在");
  42. e.printStackTrace();
  43. } catch (InstantiationException e) {
  44. e.printStackTrace();
  45. } catch (IllegalAccessException e) {
  46. e.printStackTrace();
  47. } catch (InvocationTargetException e) {
  48. e.printStackTrace();
  49. } catch (NoSuchMethodException e) {
  50. e.printStackTrace();
  51. }
  52. return null;
  53. }

属性自动装配

根据属性名事项自动装配,如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。

  1. /**
  2. * Created By zby on 21:16 2019/3/1
  3. * 根据属性名事项自动装配,
  4. * @param classPath 类路径
  5. * @param configFile 配置文件
  6. */
  7. private Object getBeanByName( String classPath, XmlConfigBean configFile) {
  8. String proName = null;
  9. try {
  10. Class currentClass = Class.forName(classPath);
  11. Class superclass = currentClass.getSuperclass();
  12. Method[] methods = currentClass.getDeclaredMethods();
  13. List<Method> methodList = MethodHelper.filterSetMethods(methods);
  14. Object currentObj = currentClass.newInstance();
  15. Set<XmlBeanProperty> properties = configFile.getProperties();
  16. //配置文件中,但是有父类,
  17. if (CollectionUtil.isEmpty(properties)) {
  18. boolean isExit = null != superclass && !superclass.getSimpleName().equals("Object");
  19. if (isExit) {
  20. Field[] parentFields = superclass.getDeclaredFields();
  21. if (ArrayUtil.isNotEmpty(parentFields)) {
  22. if (CollectionUtil.isNotEmpty(methodList)) {
  23. for (Field parentField : parentFields) {
  24. for (Method method : methodList) {
  25. if (MethodHelper.methodNameToProName(method.getName()).equals(parentField.getName())) {
  26. //如果有泛型的话
  27. Type genericType = currentClass.getGenericSuperclass();
  28. if (null != genericType) {
  29. String genericName = genericType.getTypeName();
  30. genericName = StringUtils.substring(genericName, genericName.indexOf("<") + 1, genericName.indexOf(">"));
  31. Class genericClass = Class.forName(genericName);
  32. method.setAccessible(true);
  33. method.invoke(currentObj, genericClass);
  34. }
  35. break;
  36. }
  37. }
  38. break;
  39. }
  40. }
  41. }
  42. }
  43. return currentObj;
  44. }
  45. //传递给父级对象 service -- 》value
  46. List<Method> tmpList = new ArrayList<>();
  47. Map<String, Object> map = new HashMap<>();
  48. Object value = null;
  49. for (XmlBeanProperty property : properties) {
  50. proName = property.getName();
  51. if (ArrayUtil.isNotEmpty(methods)) {
  52. String ref = property.getRef();
  53. value = property.getValue();
  54. for (Method method : methodList) {
  55. String methodName = MethodHelper.methodNameToProName(method.getName());
  56. Field field = currentClass.getDeclaredField(methodName);
  57. if (methodName.equals(proName) && null != field) {
  58. if (null == value && StringUtils.isNotBlank(ref)) {
  59. value = getBean(ref);
  60. } else if (value != null && StringUtils.isBlank(ref)) {
  61. value = Transfomer.transformerPropertyValue(field.getType().getSimpleName(), value);
  62. }
  63. method.setAccessible(true);
  64. method.invoke(currentObj, value);
  65. map.put(proName, value);
  66. tmpList.add(method);
  67. break;
  68. }
  69. }
  70. }
  71. }
  72. tmpList = MethodHelper.removeMethod(methodList, tmpList);
  73. for (Method method : tmpList) {
  74. Class<?>[] type = method.getParameterTypes();
  75. if (ArrayUtil.isEmpty(type)) {
  76. throw new RuntimeException("传递给父级对象的参数为空type=" + type);
  77. }
  78. for (Class<?> aClass : type) {
  79. String superName = ClassHelper.classNameToProName(aClass.getSimpleName());
  80. value = map.get(superName);
  81. method.setAccessible(true);
  82. method.invoke(currentObj, value);
  83. }
  84. }
  85. return currentObj;
  86. } catch (ClassNotFoundException e) {
  87. logger.error("名为" + classPath + "类不存在");
  88. e.printStackTrace();
  89. } catch (InstantiationException e) {
  90. e.printStackTrace();
  91. } catch (IllegalAccessException e) {
  92. e.printStackTrace();
  93. } catch (InvocationTargetException e) {
  94. e.printStackTrace();
  95. } catch (NoSuchFieldException e) {
  96. logger.error("类" + classPath + "属性" + proName + "不存在");
  97. e.printStackTrace();
  98. }
  99. return null;
  100. }

总结

这里没有使用注解,但我们也可以使用注解的方式实现自动装配,但这并不是spring的核心,应该是spring的美化,核心值如何实现自动装配。

发表评论

表情:
评论列表 (有 0 条评论,197人围观)

还没有评论,来说两句吧...

相关阅读