• Spring-手写模拟Spring底层原理


    概述

    模拟大致的底层原理,为学习Spring源码做铺垫。

    实现的功能:扫描路径、依赖注入、aware回调、初始化前、初始化、初始化后、切面

    未实现的功能:构造器推断、循环依赖

    重点:BeanDefinition、BeanPostProcessor

    学习Spring源码的重点:设计模式、编码规范、设计思想、扩展点

    启动类:

    1. public class Yeah
    2. {
    3. public static void main(String[] args)
    4. {
    5. GaxApplicationContext gaxApplicationContext = new GaxApplicationContext(AppConfig.class);
    6. UserInterface userService = (UserInterface) gaxApplicationContext.getBean("userService");
    7. userService.test();
    8. }
    9. }

    关键方法:

    1. public class GaxApplicationContext
    2. {
    3. private Class configClass;
    4. private static final String SINGLETON = "singleton";
    5. private Map beanDefinitionMap = new HashMap<>();
    6. private Map singletonObjects = new HashMap<>();
    7. // Spring源码用的是LinkedList
    8. private List beanPostProcessorList = new ArrayList<>();
    9. public GaxApplicationContext(Class configClass)
    10. {
    11. this.configClass = configClass;
    12. // 扫描指定路径,找到所有@Component注解的类,封装成beanDefinition保存再Map中
    13. scan(configClass);
    14. // 思考个问题:beanDefinitionMap.keySet()和beanDefinitionMap.entrySet()两种遍历的区别?选用哪个好?
    15. for (Map.Entry entry : beanDefinitionMap.entrySet())
    16. {
    17. String beanName = entry.getKey();
    18. BeanDefinition beanDefinition = entry.getValue();
    19. if (SINGLETON.equals(beanDefinition.getScope()))
    20. {
    21. Object bean = createBean(beanName, beanDefinition);
    22. singletonObjects.put(beanName, bean);
    23. }
    24. }
    25. }
    26. private Object createBean(String beanName, BeanDefinition beanDefinition)
    27. {
    28. Class clazz = beanDefinition.getType();
    29. Object instance = null;
    30. try
    31. {
    32. // 直接使用默认的无参构造器,多个构造器的场景未实现
    33. instance = clazz.getConstructor().newInstance();
    34. // 属性填充,依赖注入
    35. for (Field field : clazz.getDeclaredFields())
    36. {
    37. if (field.isAnnotationPresent(Autowired.class))
    38. {
    39. field.setAccessible(true);
    40. field.set(instance, getBean(field.getName()));
    41. }
    42. }
    43. // aware回调
    44. if (instance instanceof BeanNameAware)
    45. {
    46. ((BeanNameAware)instance).setBeanName(beanName);
    47. }
    48. // 初始化前
    49. for (BeanPostProcessor beanPostProcessor : beanPostProcessorList)
    50. {
    51. instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
    52. }
    53. // 初始化
    54. if (instance instanceof InitializingBean)
    55. {
    56. ((InitializingBean)instance).afterPropertiesSet();
    57. }
    58. // 初始化后
    59. for (BeanPostProcessor beanPostProcessor : beanPostProcessorList)
    60. {
    61. instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
    62. }
    63. }
    64. catch (InstantiationException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e)
    65. {
    66. e.printStackTrace();
    67. }
    68. return instance;
    69. }
    70. public Object getBean(String beanName)
    71. {
    72. if (!beanDefinitionMap.containsKey(beanName))
    73. {
    74. throw new NullPointerException();
    75. }
    76. BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
    77. if (SINGLETON.equals(beanDefinition.getScope()))
    78. {
    79. Object singletonBean = singletonObjects.get(beanName);
    80. if (null == singletonBean)
    81. {
    82. singletonBean = createBean(beanName, beanDefinition);
    83. singletonObjects.put(beanName, singletonBean);
    84. }
    85. return singletonBean;
    86. }
    87. else
    88. {
    89. // 原型Bean
    90. Object prototypeBean = createBean(beanName, beanDefinition);
    91. return prototypeBean;
    92. }
    93. }
    94. private void scan(Class configClass)
    95. {
    96. if (configClass.isAnnotationPresent(ComponentScan.class))
    97. {
    98. ComponentScan componentScanAnnotation = (ComponentScan)configClass.getAnnotation(ComponentScan.class);
    99. String path = componentScanAnnotation.value();
    100. // path = com/gax/service
    101. path = path.replace(".", "/");
    102. ClassLoader classLoader = GaxApplicationContext.class.getClassLoader();
    103. URL resource = classLoader.getResource(path);
    104. assert resource != null;
    105. File file = new File(resource.getFile());
    106. if (file.isDirectory())
    107. {
    108. for (File f : Objects.requireNonNull(file.listFiles()))
    109. {
    110. String absolutePath = f.getAbsolutePath();
    111. absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
    112. // 类加载器入参需要的格式:com.gax.service.XXX
    113. absolutePath = absolutePath.replace("\\", ".");
    114. try
    115. {
    116. Class clazz = classLoader.loadClass(absolutePath);
    117. if (clazz.isAnnotationPresent(Component.class))
    118. {
    119. if (BeanPostProcessor.class.isAssignableFrom(clazz))
    120. {
    121. BeanPostProcessor instance = (BeanPostProcessor)clazz.getConstructor().newInstance();
    122. beanPostProcessorList.add(instance);
    123. }
    124. Component componentAnnotation = clazz.getAnnotation(Component.class);
    125. String beanName = componentAnnotation.value();
    126. if ("".equals(beanName))
    127. {
    128. // 默认beanName
    129. beanName = Introspector.decapitalize(clazz.getSimpleName());
    130. }
    131. BeanDefinition beanDefinition = new BeanDefinition();
    132. beanDefinition.setType(clazz);
    133. if (clazz.isAnnotationPresent(Scope.class))
    134. {
    135. Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
    136. String value = scopeAnnotation.value();
    137. beanDefinition.setScope(value);
    138. }
    139. else
    140. {
    141. // 默认单例Bean
    142. beanDefinition.setScope(SINGLETON);
    143. }
    144. beanDefinitionMap.put(beanName, beanDefinition);
    145. }
    146. }
    147. catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException
    148. | InstantiationException | IllegalAccessException e)
    149. {
    150. e.printStackTrace();
    151. }
    152. }
    153. }
    154. }
    155. }
    156. }

    gitee地址:

    git clone https://gitee.com/seek6174/spring-seek.git

  • 相关阅读:
    Word控件Spire.Doc 【文本】教程(15) ;如何在 C#、VB.NET 的组合框中添加、选择和删除项目
    数学分析:数项级数的概念
    【深度学习】单隐层神经网络
    数据结构与算法编程题8
    DHCP是什么?一文详解其工作过程及配置
    TI CC2642R 平台开发
    10.Redis系列之数据类型GeoSpatial
    看了就会,幼儿园赶快学习这个技术吧
    28、Java高级特性——集合:Set接口、HashSet集合、Map接口、 Map集合
    【广度优先搜索】leetcode 107. 二叉树的层序遍历 II
  • 原文地址:https://blog.csdn.net/weixin_58482311/article/details/134067033