依赖倒置原则要求业务逻辑只依赖接口而非具体实现,接口由业务方在domain或application层定义,底层实现由技术方在infrastructure层提供,通过构造器注入解耦,确保编译期无技术细节硬依赖。

核心是让业务逻辑只依赖接口,不碰具体实现类——接口由业务方定义,实现由技术方提供,编译期就切断对数据库、HTTP客户端等细节的硬绑定。
明确谁是高层、谁是底层
高层模块指处理业务规则的部分,比如 OrderService、PaymentService;底层模块指做具体事情的部分,比如 MySQLUserRepository、RabbitMQMessageSender。关键不是包名或位置,而是谁调用谁、谁决定契约。如果 OrderService 里写了 new MySQLUserRepository() 或 import 了 com.mysql.cj.jdbc.Driver,那就已经违反了依赖倒置。
把接口定义在业务层
接口必须由高层模块“拥有”,不能放在 infrastructure 或 adapter 模块里让底层反向定义。例如:
- 在
domain或application包下定义UserRepository接口,只含findById(Long id)、save(User user)这类业务语义方法 - 避免出现
findByNameLike(String pattern)这种带 SQL 特性的方法,否则会把 MySQL 的能力契约强加给 MongoDB 实现 - 接口里不写任何 JDBC、Redis、日志等基础设施相关代码,保持纯粹的业务契约
用构造器注入代替 new 实例
高层类不自己创建底层对象,而是通过外部传入:
-
OrderService的构造函数接收UserRepository类型参数,内部只调用接口方法 - 具体实现(如
PostgreSQLUserRepository)放在infrastructure模块,实现该接口并封装 SQL、连接池、异常转换等细节 - Spring 中用
@Bean或@ConditionalOnClass注入实现,但OrderService.java文件里不能出现任何数据库驱动或消息队列的 import
验证是否真正解耦
一个简单判断方式:删掉项目中某个技术依赖(比如 spring-boot-starter-data-redis),如果 PaymentService 编译失败,说明它直接依赖了 Redis 实现,还没做到依赖倒置。真正的解耦体现在编译依赖图上——高层模块的 pom.xml 只该有领域模型和接口,不该有任何数据库、缓存、RPC 客户端的坐标。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











