参考源

https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click

https://www.bilibili.com/video/BV12Z4y197MU?spm_id_from=333.999.0.0

《Spring源码深度解析(第2版)》

版本

本文章基于 Spring 5.3.15


项目地址

https://gitee.com/liao-hang/hand-write-spring.git

模拟 Spring

注解

自动装配

Autowired

  1. @Target(ElementType.FIELD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface Autowired {
  4. }

组件

Component

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface Component {
  4. String value() default "";
  5. }

组件扫描

ComponentScan

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface ComponentScan {
  4. String value() default "";
  5. }

范围

Scope

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface Scope {
  4. String value() default "";
  5. }

Bean 定义信息

BeanDefinition

  1. public class BeanDefinition {
  2. /**
  3. * 类型
  4. */
  5. private Class type;
  6. /**
  7. * 范围
  8. */
  9. private String scope;
  10. public Class getType() {
  11. return type;
  12. }
  13. public void setType(Class type) {
  14. this.type = type;
  15. }
  16. public String getScope() {
  17. return scope;
  18. }
  19. public void setScope(String scope) {
  20. this.scope = scope;
  21. }
  22. }

Bean 名称感知

BeanNameAware

  1. public interface BeanNameAware {
  2. /**
  3. * 设置 Bean 名称
  4. * @param beanName Bean名称
  5. */
  6. void setBeanName(String beanName);
  7. }

Bean 后置处理器

BeanPostProcessor

  1. public interface BeanPostProcessor {
  2. /**
  3. * 初始化前
  4. * @param beanName Bean名称
  5. * @param bean Bean对象
  6. * @return
  7. */
  8. Object postProcessBeforeInitialization(String beanName, Object bean);
  9. /**
  10. * 初始化后
  11. * @param beanName Bean名称
  12. * @param bean Bean对象
  13. * @return
  14. */
  15. Object postProcessAfterInitialization(String beanName, Object bean);
  16. }

初始化 Bean

InitializationBean

  1. public interface InitializationBean {
  2. /**
  3. * 属性设置后
  4. */
  5. void afterPropertiesSet();
  6. }

注解配置应用上下文

AnnotationConfigApplicationContext

  1. public class AnnotationConfigApplicationContext {
  2. /**
  3. * 配置的类
  4. */
  5. private Class configClass;
  6. /**
  7. * Bean 后置处理器列表
  8. */
  9. private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
  10. /**
  11. * Bean 定义信息池
  12. */
  13. private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
  14. /**
  15. * 单例池
  16. */
  17. private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
  18. public AnnotationConfigApplicationContext(Class configClass) {
  19. this.configClass = configClass;
  20. /*
  21. 扫描 -> BeanDefinition -> beanDefinitionMap
  22. */
  23. // 是否有 @ComponentScan 注解
  24. if (configClass.isAnnotationPresent(ComponentScan.class)) {
  25. ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
  26. // 注解中的路径
  27. String path = componentScan.value();
  28. // 处理路径
  29. path = path.replace(".", "/");
  30. // 类加载器
  31. ClassLoader classLoader = AnnotationConfigApplicationContext.class.getClassLoader();
  32. // 资源
  33. URL resource = classLoader.getResource(path);
  34. // 文件
  35. File file = new File(resource.getFile());
  36. // 如果为目录
  37. if (file.isDirectory()) {
  38. // 文件列表
  39. File[] files = file.listFiles();
  40. for (File f : files) {
  41. // 绝对路径
  42. String fileName = f.getAbsolutePath();
  43. // 是否为 class 文件
  44. if (fileName.endsWith(".class")) {
  45. // 类名 cn\sail\test\文件名
  46. String className = fileName.substring(fileName.indexOf("cn"), fileName.indexOf(".class"));
  47. // 处理路径
  48. className = className.replace("\\", ".");
  49. try {
  50. Class<?> clazz = classLoader.loadClass(className);
  51. // 是否有 @Component 注解
  52. if (clazz.isAnnotationPresent(Component.class)) {
  53. // 接口和类是否相同或者是否为其超类或超接口
  54. if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
  55. BeanPostProcessor instance = (BeanPostProcessor) clazz.newInstance();
  56. beanPostProcessorList.add(instance);
  57. }
  58. Component component = clazz.getAnnotation(Component.class);
  59. String beanName = component.value();
  60. if ("".equals(beanName)) {
  61. beanName = Introspector.decapitalize(clazz.getSimpleName());
  62. }
  63. BeanDefinition beanDefinition = new BeanDefinition();
  64. beanDefinition.setType(clazz);
  65. // 是否有 @Scope 注解
  66. if (clazz.isAnnotationPresent(Scope.class)) {
  67. // 如果有,以传入的模式为准
  68. Scope scope = clazz.getAnnotation(Scope.class);
  69. beanDefinition.setScope(scope.value());
  70. } else {
  71. // 如果没有,默认为单例模式
  72. beanDefinition.setScope("singleton");
  73. }
  74. beanDefinitionMap.put(beanName, beanDefinition);
  75. }
  76. } catch (ClassNotFoundException e) {
  77. e.printStackTrace();
  78. } catch (InstantiationException e) {
  79. e.printStackTrace();
  80. } catch (IllegalAccessException e) {
  81. e.printStackTrace();
  82. }
  83. }
  84. }
  85. }
  86. }
  87. // 实例化单例 Bean
  88. for (String beanName : beanDefinitionMap.keySet()) {
  89. BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
  90. // 如果为单例模式,将 BeanDefinition 放入单例池中,下次直接从池中取,以保证单例
  91. if ("singleton".equals(beanDefinition.getScope())) {
  92. Object bean = createBean(beanName, beanDefinition);
  93. singletonObjects.put(beanName, bean);
  94. }
  95. }
  96. }
  97. /**
  98. * 创建 Bean
  99. * @param beanName Bean 名称
  100. * @param beanDefinition Bean 定义信息
  101. * @return Bean 对象
  102. */
  103. private Object createBean(String beanName, BeanDefinition beanDefinition) {
  104. Class clazz = beanDefinition.getType();
  105. try {
  106. Object instance = clazz.getConstructor().newInstance();
  107. // 依赖注入
  108. for (Field f : clazz.getDeclaredFields()) {
  109. // 是否有 @Autowired 注解
  110. if (f.isAnnotationPresent(Autowired.class)) {
  111. // 忽略访问修饰符限制
  112. f.setAccessible(true);
  113. // 注入
  114. f.set(instance, getBean(f.getName()));
  115. }
  116. }
  117. // Aware
  118. if (instance instanceof BeanNameAware) {
  119. ((BeanNameAware) instance).setBeanName(beanName);
  120. }
  121. // 初始化前
  122. for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
  123. instance = beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
  124. }
  125. // 初始化
  126. if (instance instanceof InitializationBean) {
  127. ((InitializationBean) instance).afterPropertiesSet();
  128. }
  129. // 初始化后
  130. for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
  131. instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
  132. }
  133. return instance;
  134. } catch (InstantiationException e) {
  135. e.printStackTrace();
  136. } catch (IllegalAccessException e) {
  137. e.printStackTrace();
  138. } catch (InvocationTargetException e) {
  139. e.printStackTrace();
  140. } catch (NoSuchMethodException e) {
  141. e.printStackTrace();
  142. }
  143. return null;
  144. }
  145. public Object getBean(String beanName) {
  146. BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
  147. if (beanDefinition == null) {
  148. throw new NullPointerException();
  149. } else {
  150. String scope = beanDefinition.getScope();
  151. if ("singleton".equals(scope)) {
  152. Object bean = singletonObjects.get(beanName);
  153. // 如果单例池中没有对应 Bean,创建 Bean 后再放入池中
  154. if (bean == null) {
  155. bean = createBean(beanName, beanDefinition);
  156. singletonObjects.put(beanName, bean);
  157. }
  158. return bean;
  159. } else {
  160. // 如果不是单例模式,直接创建 Bean
  161. return createBean(beanName, beanDefinition);
  162. }
  163. }
  164. }
  165. }

使用 Spring

应用配置

AppConfig

  1. @ComponentScan("cn.sail.test")
  2. public class AppConfig {
  3. }

用户服务

UserInterface

  1. public interface UserInterface {
  2. /**
  3. * 测试
  4. */
  5. void test();
  6. }

用户服务实现类

UserService

  1. @Component
  2. public class UserService implements UserInterface{
  3. @Autowired
  4. private OrderService orderService;
  5. @Override
  6. public void test() {
  7. System.out.println(orderService);
  8. }
  9. }

排序服务

OrderService

  1. @Component
  2. public class OrderService {
  3. }

Bean 后置处理器

MyBeanPostProcessor

  1. @Component
  2. public class MyBeanPostProcessor implements BeanPostProcessor {
  3. /**
  4. * 初始化前
  5. *
  6. * @param beanName
  7. * @param bean
  8. * @return
  9. */
  10. @Override
  11. public Object postProcessBeforeInitialization(String beanName, Object bean) {
  12. if ("userService".equals(beanName)) {
  13. System.out.println("1111");
  14. }
  15. return bean;
  16. }
  17. /**
  18. * 初始化后
  19. *
  20. * @param beanName
  21. * @param bean
  22. * @return
  23. */
  24. @Override
  25. public Object postProcessAfterInitialization(String beanName, Object bean) {
  26. if ("userService".equals(beanName)) {
  27. Object proxyInstance = Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
  28. @Override
  29. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  30. System.out.println("切面逻辑");
  31. return method.invoke(bean, args);
  32. }
  33. });
  34. return proxyInstance;
  35. }
  36. return bean;
  37. }
  38. }

测试

Test

  1. public class Test {
  2. public static void main(String[] args) {
  3. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  4. UserInterface userService = (UserInterface) applicationContext.getBean("userService");
  5. userService.test();
  6. }
  7. }

Spring源码 20 手写模拟源码的更多相关文章

  1. 手写koa-static源码,深入理解静态服务器原理

    这篇文章继续前面的Koa源码系列,这个系列已经有两篇文章了: 第一篇讲解了Koa的核心架构和源码:手写Koa.js源码 第二篇讲解了@koa/router的架构和源码:手写@koa/router源码 ...

  2. 【Spring系列】- 手写模拟Spring框架

    简单模拟Spring 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! 前言 上次已经学习了 ...

  3. 《四 spring源码》手写springioc框架

    手写SpringIOCXML版本 /** * 手写Spring专题 XML方式注入bean * * * */ public class ClassPathXmlApplicationContext { ...

  4. 《四 spring源码》手写springmvc

    手写SpringMVC思路 1.web.xml加载  为了读取web.xml中的配置,我们用到ServletConfig这个类,它代表当前Servlet在web.xml中的配置信息.通过web.xml ...

  5. 面试必会之ArrayList源码分析&手写ArrayList

    简介 ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高. 线程 ...

  6. 手写Redux-Saga源码

    上一篇文章我们分析了Redux-Thunk的源码,可以看到他的代码非常简单,只是让dispatch可以处理函数类型的action,其作者也承认对于复杂场景,Redux-Thunk并不适用,还推荐了Re ...

  7. Spring事务原理分析--手写Spring事务

    一.基本概念和原理 1.Spring事务 基于AOP环绕通知和异常通知的 2.Spring事务分为编程式事务.声明事务.编程事务包括注解方式和扫包方式(xml) Spring事务底层使用编程事务(自己 ...

  8. Spring源码分析 手写简单IOC容器

    Spring的两大特性就是IOC和AOP. IOC Container,控制反转容器,通过读取配置文件或注解,将对象封装成Bean存入IOC容器待用,程序需要时再从容器中取,实现控制权由程序员向程序的 ...

  9. 源码分析 | 手写mybait-spring核心功能(干货好文一次学会工厂bean、类代理、bean注册的使用)

    作者:小傅哥 博客:https://bugstack.cn - 汇总系列原创专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言介绍 一个知识点的学习过程基本分为:运行helloworld ...

随机推荐

  1. 定制ASP.NET 6.0的应用配置

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本文的主题是应用程序配置.要介绍的是如何使用配置.如何自定义配置,以采用不同的方式 ...

  2. 计算机网络 - HTTP和HTTPS的区别

    计算机网络 - HTTP和HTTPS的区别 http所有传输的内容都是明文,并且客户端和服务器端都无法验证对方的身份. https具有安全性的ssl加密传输协议,加密采用对称加密. https协议需要 ...

  3. 解惑unittest框架中导入HTMLTestRunner模块后正常运行却无法生成HTML报告问题

    1.HTMLTestRunner介绍 HTMLTestRunner是一个第三方的unittest HTML报告库,用于python单元测试框架的TestRunner.它是生成一个HTML报告,以一目了 ...

  4. 我所使用的生产 Java 17 启动参数

    JVM 参数升级提示工具:jacoline.dev/inspect JVM 参数词典:chriswhocodes.com Revolut(英国支付巨头)升级 Java 17 实战:https://ww ...

  5. mysql5.7安装要踩的坑

    因为官网下载的是绿色版,所以要做一些配置 1.在mysql根目录新增data文件夹和my.ini文件 my.ini文件内容 [mysql]# 设置mysql客户端默认字符集default-charac ...

  6. Python Excel 操作

    1.Excel Code import os import time import re import win32com.client def dealpath(pathname='') -> ...

  7. SAP OLE download to excel

    REPORT RSDEMO01 NO STANDARD PAGE HEADING. * this report demonstrates how to send some ABAP data to a ...

  8. SpringCloud Alibaba整合Sentinel

    SpringCloud Alibaba整合Sentinel Sentinel 控制台 1. 概述 Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理.监控(单机和集群),规则 ...

  9. vue 的常用事件

    vue 的常用事件 事件处理 1.使用 v-on:xxx 或 @xxx 绑定事件,其中 xxx 是事件名: 2.事件的回调需要配置在 methods 对象中,最终会在 vm 上: 3.methods ...

  10. python常见的错误提示处理

    python常见的错误有 NameError变量名错误 IndentationError代码缩进错误 AttributeError对象属性错误 TypeError类型错误 IOError输入输出错误 ...