Spring Boot中用接口引用调用非静态未实现方法的疑问
嘿,这个问题问得特别到位!我刚上手Spring Data JPA的时候,也对着这个“凭空出现”的实现懵了好久😅,这其实是Spring框架给我们的一个大大的便利——动态代理+Spring Data JPA的自动实现机制,咱们一步步拆解:
1. 你的IArticleDAO其实不是普通的Java接口
在你跟着的教程里,IArticleDAO应该是继承了Spring Data JPA提供的JpaRepository(或者CrudRepository)这类基础接口对吧?比如类似这样:
public interface IArticleDAO extends JpaRepository<Article, Long> { // 自定义的查询方法,比如 findByTitle(String title) }
一旦继承了这些Spring提供的Repository接口,这个接口就被Spring“标记”为需要自动生成实现类的特殊接口了。
2. Spring启动时会自动生成代理实现类
当你的Spring Boot项目启动时,Spring会扫描所有继承了Repository接口的类,然后通过动态代理技术(比如JDK动态代理或者CGLIB)在运行时为IArticleDAO生成一个真实的实现类。这个实现类里已经帮你写好了所有CRUD方法的逻辑(比如save()、findAll()、deleteById()),甚至连你自定义的查询方法(比如根据标题查询),Spring都会根据方法名自动解析生成对应的SQL和执行逻辑。
3. 你调用的其实是代理对象的方法
在ArticleService里,你注入的IArticleDAO引用,看起来是接口类型,但实际上指向的是Spring动态生成的那个代理对象。比如你写:
@Service public class ArticleService { private final IArticleDAO articleDAO; // 构造注入(或者@Autowired) public ArticleService(IArticleDAO articleDAO) { this.articleDAO = articleDAO; } public List<Article> getAllArticles() { return articleDAO.findAll(); // 这里调用的是代理对象的findAll()实现 } }
这里的articleDAO并不是空的接口,而是Spring已经帮你实例化好的代理对象,所以调用方法时自然能执行并返回结果。
4. 简单总结一下
- 普通Java接口确实不能直接调用未实现的方法,但你的
IArticleDAO是Spring Data JPA的特殊接口 - Spring在运行时为它动态生成了实现类(代理对象)
- 通过依赖注入,
ArticleService拿到的是这个代理对象的引用,所以能正常调用方法
是不是瞬间就清晰了?这就是Spring Data JPA能让我们少写很多重复CRUD代码的核心魔力~
内容的提问来源于stack exchange,提问作者MOG

