1. Java 基础层面
接口(Interface) 只是方法的定义/规范,里面没有真正的逻辑。
例如:
public interface IBookService {boolean save(Book book); }
👉 这里只说明了:我要有一个
save
方法,但“怎么保存”没有写。实现类(Implementation) 才是具体干活的地方:
@Service public class BookServiceImpl implements IBookService {@Overridepublic boolean save(Book book) {// 真正调用 Mapper/DAO 去执行 INSERT 语句return baseMapper.insert(book) > 0;} }
如果只有接口没有实现类,那么调用 bookService.save(book)
时就会找不到“怎么执行”的逻辑,运行时会报错。
2. 在 MyBatis-Plus 里
MyBatis-Plus 已经帮我们准备好了一套通用实现逻辑:
接口:
IService<T>
(定义了常见 CRUD 方法)实现类:
ServiceImpl<M,T>
(帮你实现了大部分方法)
所以我们才会写:
public interface IBookService extends IService<Book> {}
@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book>implements IBookService {}
这样你就获得了很多现成的方法:
bookService.save(book)
bookService.updateById(book)
bookService.removeById(id)
bookService.page(page)
……
👉 如果你只写 IBookService
,没有对应的 BookServiceImpl
,Spring 容器里就不会有一个真正的 Bean 去执行这些方法,你的 @Autowired
注入就会失败(报 NoSuchBeanDefinitionException
)。
3. 为什么不直接用接口?
接口是规范,解耦:上层代码依赖接口而不是实现,方便以后换不同实现。
有了接口,你可以有多个实现类,比如:
BookServiceImpl
→ 使用 MyBatis-Plus 访问数据库BookServiceCacheImpl
→ 带缓存逻辑BookServiceMockImpl
→ 测试用的假实现
这样 Controller 层代码完全不用改,只要注入不同实现即可。
4. 总结
接口 = 定义功能(做什么)
实现类 = 实现功能(怎么做)
在 Spring/MP 项目里,接口让你分层清晰、依赖解耦;实现类让系统真正能运行。
👉 所以:
IBookService
是抽象的“业务契约”,
BookServiceImpl
是具体的“业务实现”,
两者配合才能在 Spring 项目中工作。