目录
-
-
- [一、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。指对象的创建、管理的控制权反转。
完整流程像"点外卖":
- 下单(扫描) :Spring 启动,像外卖平台一样,先扫描你电脑里哪些类上有
@Component、@Service等注解,把它们记下来。 - 建菜单(BeanDefinition) :Spring 不直接做饭,它先记个"菜单":这个菜(类)叫什么、需要什么配料(依赖,比如
@Autowired注入的对象)。 - 做饭(实例化):到了饭点,Spring 开始动手。先反射调用构造方法,把空的对象(菜)做出来。
- 加配料(依赖注入 DI):菜做好了,发现缺盐缺醋,再把依赖的对象注入进去,把对象补全。
- 装盘(初始化) :最后检查一下,执行一些初始化方法(比如
@PostConstruct),然后把这个完美的菜放进保温柜(单例池singletonObjects)。 - 取餐(使用):你要用的时候,直接去保温柜里拿,永远是热的。
核心原理:三级缓存解决循环依赖
如果 A 依赖 B,B 又依赖 A,怎么避免死循环?
Spring 用了三级缓存(三个 Map):
- 一级缓存:放成品(A 造好了)。
- 二级缓存:放半成品(A 刚造出来,还没加配料,但地址已经有了)。
- 三级缓存 :放工厂(能生成半成品的方法)。
这样 B 拿到 A 的半成品地址,就能先继续自己的创建流程。
2. AOP(面向切面)(Aspect Oriented Programming):给代码加"监控"
目标:在不修改原代码的情况下,给方法加日志、事务、权限控制。
完整流程像"高速公路收费站":
- 规划收费站(定义切面) :你定义一个类,加上
@Aspect,声明哪些路段要收费(切点@Pointcut,比如com.xxx.service..*.*(..)),以及什么时候收费(通知@Before前置、@After后置、@Around环绕)。 - 安装收费站(代理创建) :当 Spring 把这个业务对象创建出来后,它不会直接给你,而是动态生成一个"替身"(代理对象)。
- 如果你的类实现了接口,用 JDK 动态代理,生成接口的实现类。
- 如果没实现接口,用 CGLIB 代理,继承这个类,生成子类。
- 经过收费站(执行流程):当你调用方法时,其实是调用了"替身"。替身会先执行你的通知逻辑(比如记录日志),然后再调用真实对象的方法,最后再处理收尾逻辑。
二、Spring MVC 请求流程:前台接待员
目标:浏览器发来一个请求,Spring 是怎么找到具体方法并返回结果的。
完整流程像"公司前台处理客户":
- 客户进门(DispatcherServlet) :所有请求都先被 Spring 的核心 Servlet
DispatcherServlet接住,它是总前台。 - 查工牌(HandlerMapping):前台立刻查名单,根据请求的 URL,找到对应的服务员(Controller 方法)。
- 找服务员(HandlerAdapter):前台知道找哪个服务员,但服务员可能很忙,需要一个适配器来帮忙协调,负责参数解析、类型转换。
- 服务执行(Controller):服务员执行具体逻辑,查数据库、处理数据。
- 打包/展示(ViewResolver/HttpMessageConverter) :
- 如果是网页,用
ViewResolver找页面渲染。 - 如果是 JSON 接口,用
HttpMessageConverter把数据变成 JSON 字符串。
- 如果是网页,用
- 送客(响应):把结果打包返回给浏览器。
三、Spring Boot 自动配置原理:懒人自动装机
目标 :我们只要引入一个 starter,写个 @SpringBootApplication 就能跑,不用写一堆 XML
核心思想:约定 > 配置 + 自动发现。
完整流程像"电脑出厂预装软件":
- 开机键(@SpringBootApplication) :这是一个组合注解,核心是
@EnableAutoConfiguration和@SpringBootConfiguration和@ComponentScan。 - 自动发现(SPI 机制) :Spring Boot 启动时,会去扫描所有 jar 包下的
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。这个文件里列了一堆自动配置类,相当于"预装软件清单"。 - 条件判断(@Conditional) :不是所有软件都装。Spring 用一系列条件注解来决定:
@ConditionalOnClass:检查你电脑里有没有这个类(比如引入了Redis依赖,才会去配置Redis客户端)。@ConditionalOnMissingBean:如果你没自己配置过这个 Bean,我才自动配置一个。@ConditionalOnProperty:检查配置文件里有没有这个配置。
- 绑定配置(@ConfigurationProperties) :自动配置类会绑定
application.yml里的配置,比如server.port、spring.datasource.url。
自定义 Starter 三步走:
- 写配置类 :写一个
@Configuration类,里面用@Bean定义你要自动配置的组件。 - 加条件 :在类或方法上加上
@Conditional注解,控制生效条件。 - 注册 SPI :在
resources目录下创建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,内容是你的配置类全限定名。打包,别人就能直接引入使用了。
四、MyBatis 执行流程:SQL 执行器
目标:接口怎么没写实现类就能执行 SQL?插件怎么生效?
1. 执行流程
- 读配置(SqlSessionFactory) :启动时,MyBatis 解析
mybatis-config.xml和Mapper.xml,生成一个工厂SqlSessionFactory。 - 开会话(SqlSession) :从工厂里获取一个会话
SqlSession,它像一个数据库连接。 - 拿代理(getMapper()) :你调用
sqlSession.getMapper(XXXMapper.class),MyBatis 用 JDK 动态代理,为这个接口生成一个代理对象。 - 执行 SQL :
- 代理对象拦截方法,根据方法名找到对应的
MappedStatement(封装了 SQL 语句、参数类型、返回类型)。 - 交给
Executor执行器去执行,底层用PreparedStatement预编译 SQL,设置参数,执行。 - 最后用
ResultSetHandler把结果集转换成 Java 对象。
- 代理对象拦截方法,根据方法名找到对应的
2. 插件机制
目标:在 SQL 执行的各个环节加自定义逻辑(比如分页、打印 SQL)。
原理:MyBatis 允许你拦截它的四大核心对象:
Executor:执行器,最顶层。ParameterHandler:参数处理器。ResultSetHandler:结果集处理器。StatementHandler:语句处理器(最核心)。
实现:
- 实现
Interceptor接口,重写intercept方法,在里面写你的逻辑。 - 用
@Intercepts和@Signature注解声明你要拦截哪个类的哪个方法。 - 注册插件(在
mybatis-config.xml里配置)。
底层也是动态代理,把你的插件包装成代理,层层拦截。
如何定位 Bug & 写自定义 Starter
-
定位框架 Bug:
- IoC/AOP 问题 :断点跟踪
AbstractBeanFactory的doGetBean方法,看 Bean 是怎么一步步创建的,代理对象是什么时候生成的。 - MVC 问题 :断点
DispatcherServlet的doDispatch方法,看请求走到哪一步卡住了。 - MyBatis 问题 :断点
BaseExecutor的query方法,看 SQL 是怎么被执行的。
- IoC/AOP 问题 :断点跟踪
-
写自定义 Starter:
- 核心就是 "自动配置类 + 条件注解 + SPI 注册"。
- 先写一个配置类,用
@Bean定义组件,加上@Conditional控制条件。 - 然后在
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里写上这个配置类的全限定名。 - 打包安装,就能被 Spring Boot 自动加载了。