Spring 与 MyBatis-Plus 配置原理:为什么实现接口就能改变框架行为
·
在使用 Spring、MyBatis-Plus 等框架时,我们经常会看到一种“神奇”的写法:
- 实现某个接口
- 重写其中的方法
- 加一个
@Component或写在配置类里然后什么都不调用,框架的行为就被改变了。
本文从原理层面解释:这是怎么做到的?
一、先给结论(一句话版)
框架通过“接口 + 默认实现 + 扩展点回调”的方式,把一部分控制权交给用户;
Spring 在启动时扫描并注册用户的实现,在框架的关键执行流程中主动回调这些实现,从而改变默认行为。
这背后,本质是 IoC(控制反转)+ 设计模式 的组合运用。
二、从一个最小模型理解“配置为什么生效”
先不看 Spring,也不看 MyBatis-Plus,先看一个极简的“框架模型”。
1. 框架定义扩展接口
public interface Formatter {
String format(String input);
}
2. 框架提供默认实现
public class DefaultFormatter implements Formatter {
@Override
public String format(String input) {
return input;
}
}
3. 框架的核心流程(你通常看不到)
public class FrameworkCore {
private Formatter formatter = new DefaultFormatter();
public void run(String data) {
String result = formatter.format(data);
System.out.println(result);
}
// 给用户预留的扩展点
public void setFormatter(Formatter formatter) {
this.formatter = formatter;
}
}
这里有一个关键点:
框架在自己的核心流程中,依赖的是接口,而不是具体实现。
三、Spring 介入后,发生了什么变化
1. 用户实现接口
@Component
public class UpperCaseFormatter implements Formatter {
@Override
public String format(String input) {
return input.toUpperCase();
}
}
2. Spring 在启动时做的事
- 扫描到
UpperCaseFormatter - 发现它实现了
Formatter接口 - 将其注册为一个 Bean
3. 框架从 Spring 容器中获取实现
Formatter formatter = applicationContext.getBean(Formatter.class);
frameworkCore.setFormatter(formatter);
结果:
- 你没有主动调用框架
- 但框架在运行流程中使用了你的实现
- 默认行为被替换
👉 功能改变了
四、MyBatis-Plus 的真实配置案例
下面以 MyBatis-Plus 中非常常见的自动填充配置为例。
1. MyBatis-Plus 定义扩展接口
public interface MetaObjectHandler {
void insertFill(MetaObject metaObject);
void updateFill(MetaObject metaObject);
}
2. 用户实现接口(配置类)
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime",
LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime",
LocalDateTime.class, LocalDateTime.now());
}
}
3. MyBatis-Plus 内部的真实逻辑(伪代码)
MetaObjectHandler handler = applicationContext.getBean(MetaObjectHandler.class);
if (handler != null) {
handler.insertFill(metaObject);
}
关键点在于:
不是你调用 MyBatis-Plus,而是 MyBatis-Plus 在固定时机回调你。
五、这背后的核心机制
1. IoC(控制反转)
- 你不再控制“什么时候调用”
- 框架控制整体流程
- 你只负责“怎么实现”
控制权从“用户代码”反转到了“框架代码”。
2. 接口 + 依赖倒置
框架代码:
@Autowired
private MetaObjectHandler metaObjectHandler;
框架只关心:
有没有人实现这个接口?
至于实现是谁、怎么实现,完全交给用户。
3. Spring 容器的角色
Spring 在这里充当的是:
扩展点发现器 + 对象管理器
- 发现你实现的接口
- 管理生命周期
- 在运行时提供给框架使用
六、涉及的设计模式(面试加分点)
1. 模板方法模式(Template Method)
框架定义固定流程
├─ beforeInsert() ← 用户实现
├─ doInsert()
└─ afterInsert() ← 用户实现
流程不可变,细节可扩展。
2. 策略模式(Strategy)
- 接口:策略抽象
- 用户实现:具体策略
- 框架在运行时选择并执行策略
3. 扩展点 / SPI 思想
- 框架预留扩展接口
- 用户实现
- 运行期自动接管行为
七、为什么“实现接口 + 重写方法”就能改功能?
归根结底只有一句话:
框架在关键执行路径中,主动调用接口方法,而接口的实现权被交给了你。
你并没有改变流程,只是替换了“流程中的某个钩子”。
八、面试 / 总结用的一句话
Spring 及其生态框架通常通过接口定义扩展点,结合 IoC 容器在启动时发现并注册用户实现,在框架的关键执行流程中进行回调,从而在不修改框架源码的情况下实现行为扩展。这本质上是 IoC 思想与模板方法、策略模式的结合。
九、结语
当你理解了这一点,就会发现:
- Spring Boot Starter 为什么“引入即生效”
- MyBatis-Plus、Spring Security 为什么配置如此灵活
- 为什么优秀框架都大量使用接口
它们的答案,其实都是同一个:
控制权在框架,定制权在用户。
更多推荐




所有评论(0)