Spring源码与框架原理

目录

      • [一、Spring IoC / AOP:工厂和管家](#一、Spring IoC / AOP:工厂和管家)
        • [1. IoC(控制反转)( Inversion of Control):Spring 就是一个超级工厂](#1. IoC(控制反转)( Inversion of Control):Spring 就是一个超级工厂)
        • [2. AOP(面向切面)(Aspect Oriented Programming):给代码加"监控"](#2. AOP(面向切面)(Aspect Oriented Programming):给代码加“监控”)
      • [二、Spring MVC 请求流程:前台接待员](#二、Spring MVC 请求流程:前台接待员)
      • [三、Spring Boot 自动配置原理:懒人自动装机](#三、Spring Boot 自动配置原理:懒人自动装机)
      • [四、MyBatis 执行流程:SQL 执行器](#四、MyBatis 执行流程:SQL 执行器)
        • [1. 执行流程](#1. 执行流程)
        • [2. 插件机制](#2. 插件机制)
      • [如何定位 Bug & 写自定义 Starter](#如何定位 Bug & 写自定义 Starter)

一、Spring IoC / AOP:工厂和管家

1. IoC(控制反转)( Inversion of Control):Spring 就是一个超级工厂

目标 :把所有对象(Bean)都扔进 Spring 容器里管理,不用你自己 new。指对象的创建、管理的控制权反转。

完整流程像"点外卖":

  1. 下单(扫描) :Spring 启动,像外卖平台一样,先扫描你电脑里哪些类上有 @Component@Service 等注解,把它们记下来。
  2. 建菜单(BeanDefinition) :Spring 不直接做饭,它先记个"菜单":这个菜(类)叫什么、需要什么配料(依赖,比如 @Autowired 注入的对象)。
  3. 做饭(实例化):到了饭点,Spring 开始动手。先反射调用构造方法,把空的对象(菜)做出来。
  4. 加配料(依赖注入 DI):菜做好了,发现缺盐缺醋,再把依赖的对象注入进去,把对象补全。
  5. 装盘(初始化) :最后检查一下,执行一些初始化方法(比如 @PostConstruct),然后把这个完美的菜放进保温柜(单例池 singletonObjects)。
  6. 取餐(使用):你要用的时候,直接去保温柜里拿,永远是热的。

核心原理:三级缓存解决循环依赖

如果 A 依赖 B,B 又依赖 A,怎么避免死循环?

Spring 用了三级缓存(三个 Map):

  • 一级缓存:放成品(A 造好了)。
  • 二级缓存:放半成品(A 刚造出来,还没加配料,但地址已经有了)。
  • 三级缓存 :放工厂(能生成半成品的方法)。
    这样 B 拿到 A 的半成品地址,就能先继续自己的创建流程。
2. AOP(面向切面)(Aspect Oriented Programming):给代码加"监控"

目标:在不修改原代码的情况下,给方法加日志、事务、权限控制。

完整流程像"高速公路收费站":

  1. 规划收费站(定义切面) :你定义一个类,加上 @Aspect,声明哪些路段要收费(切点 @Pointcut,比如 com.xxx.service..*.*(..)),以及什么时候收费(通知 @Before 前置、@After 后置、@Around 环绕)。
  2. 安装收费站(代理创建) :当 Spring 把这个业务对象创建出来后,它不会直接给你,而是动态生成一个"替身"(代理对象)。
    • 如果你的类实现了接口,用 JDK 动态代理,生成接口的实现类。
    • 如果没实现接口,用 CGLIB 代理,继承这个类,生成子类。
  3. 经过收费站(执行流程):当你调用方法时,其实是调用了"替身"。替身会先执行你的通知逻辑(比如记录日志),然后再调用真实对象的方法,最后再处理收尾逻辑。

二、Spring MVC 请求流程:前台接待员

目标:浏览器发来一个请求,Spring 是怎么找到具体方法并返回结果的。

完整流程像"公司前台处理客户":

  1. 客户进门(DispatcherServlet) :所有请求都先被 Spring 的核心 Servlet DispatcherServlet 接住,它是总前台。
  2. 查工牌(HandlerMapping):前台立刻查名单,根据请求的 URL,找到对应的服务员(Controller 方法)。
  3. 找服务员(HandlerAdapter):前台知道找哪个服务员,但服务员可能很忙,需要一个适配器来帮忙协调,负责参数解析、类型转换。
  4. 服务执行(Controller):服务员执行具体逻辑,查数据库、处理数据。
  5. 打包/展示(ViewResolver/HttpMessageConverter)
    • 如果是网页,用 ViewResolver 找页面渲染。
    • 如果是 JSON 接口,用 HttpMessageConverter 把数据变成 JSON 字符串。
  6. 送客(响应):把结果打包返回给浏览器。

三、Spring Boot 自动配置原理:懒人自动装机

目标 :我们只要引入一个 starter,写个 @SpringBootApplication 就能跑,不用写一堆 XML

核心思想:约定 > 配置 + 自动发现

完整流程像"电脑出厂预装软件":

  1. 开机键(@SpringBootApplication) :这是一个组合注解,核心是 @EnableAutoConfiguration@SpringBootConfiguration@ComponentScan
  2. 自动发现(SPI 机制) :Spring Boot 启动时,会去扫描所有 jar 包下的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件。这个文件里列了一堆自动配置类,相当于"预装软件清单"。
  3. 条件判断(@Conditional) :不是所有软件都装。Spring 用一系列条件注解来决定:
    • @ConditionalOnClass:检查你电脑里有没有这个类(比如引入了 Redis 依赖,才会去配置 Redis 客户端)。
    • @ConditionalOnMissingBean:如果你没自己配置过这个 Bean,我才自动配置一个。
    • @ConditionalOnProperty:检查配置文件里有没有这个配置。
  4. 绑定配置(@ConfigurationProperties) :自动配置类会绑定 application.yml 里的配置,比如 server.portspring.datasource.url

自定义 Starter 三步走

  1. 写配置类 :写一个 @Configuration 类,里面用 @Bean 定义你要自动配置的组件。
  2. 加条件 :在类或方法上加上 @Conditional 注解,控制生效条件。
  3. 注册 SPI :在 resources 目录下创建 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,内容是你的配置类全限定名。打包,别人就能直接引入使用了。

四、MyBatis 执行流程:SQL 执行器

目标:接口怎么没写实现类就能执行 SQL?插件怎么生效?

1. 执行流程
  1. 读配置(SqlSessionFactory) :启动时,MyBatis 解析 mybatis-config.xmlMapper.xml,生成一个工厂 SqlSessionFactory
  2. 开会话(SqlSession) :从工厂里获取一个会话 SqlSession,它像一个数据库连接。
  3. 拿代理(getMapper()) :你调用 sqlSession.getMapper(XXXMapper.class),MyBatis 用 JDK 动态代理,为这个接口生成一个代理对象。
  4. 执行 SQL
    • 代理对象拦截方法,根据方法名找到对应的 MappedStatement(封装了 SQL 语句、参数类型、返回类型)。
    • 交给 Executor 执行器去执行,底层用 PreparedStatement 预编译 SQL,设置参数,执行。
    • 最后用 ResultSetHandler 把结果集转换成 Java 对象。
2. 插件机制

目标:在 SQL 执行的各个环节加自定义逻辑(比如分页、打印 SQL)。

原理:MyBatis 允许你拦截它的四大核心对象:

  • Executor:执行器,最顶层。
  • ParameterHandler:参数处理器。
  • ResultSetHandler:结果集处理器。
  • StatementHandler:语句处理器(最核心)。

实现

  1. 实现 Interceptor 接口,重写 intercept 方法,在里面写你的逻辑。
  2. @Intercepts@Signature 注解声明你要拦截哪个类的哪个方法。
  3. 注册插件(在 mybatis-config.xml 里配置)。
    底层也是动态代理,把你的插件包装成代理,层层拦截。

如何定位 Bug & 写自定义 Starter

  1. 定位框架 Bug

    • IoC/AOP 问题 :断点跟踪 AbstractBeanFactorydoGetBean 方法,看 Bean 是怎么一步步创建的,代理对象是什么时候生成的。
    • MVC 问题 :断点 DispatcherServletdoDispatch 方法,看请求走到哪一步卡住了。
    • MyBatis 问题 :断点 BaseExecutorquery 方法,看 SQL 是怎么被执行的。
  2. 写自定义 Starter

    • 核心就是 "自动配置类 + 条件注解 + SPI 注册"
    • 先写一个配置类,用 @Bean 定义组件,加上 @Conditional 控制条件。
    • 然后在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件里写上这个配置类的全限定名。
    • 打包安装,就能被 Spring Boot 自动加载了。
相关推荐
王家视频教程图书馆1 小时前
rust 写gui 程序 最流行的是哪个
开发语言·后端·rust
Lyyaoo.1 小时前
【JAVA基础面经】线程安全的单例模式
java·安全·单例模式
_李小白2 小时前
【OSG学习笔记】Day 39: NodeCallback(帧回调机制)
java·笔记·学习
如来神掌十八式2 小时前
设计模式之装饰器模式
java·设计模式
好大哥呀2 小时前
如何在Spring Boot中配置数据库连接?
数据库·spring boot·后端
cch89182 小时前
C++、Python与汇编语言终极对比
java·开发语言·jvm
老神在在0012 小时前
企业级 SpringBoot 后端通用开发规范|统一响应 + 敏感字段加密
spring boot·后端·状态模式
tsyjjOvO2 小时前
【Spring Data Redis 从入门到实战】一站式掌握 Redis 操作与封装
redis·spring
csdn_aspnet2 小时前
在 ASP.NET Core (WebAPI) 中启用 CORS
后端·asp.net·.netcore