2016年 5月 9日
spring-data-jpa源码阅读笔记:Repository方法名查询推导(Query Derivation From Method Names)的实现原理
Repository方法名查询推导(Query Derivation From Method Names)的实现原理
Repository的默认实现
从spring-data-jpa的源代码中可以看到,Repository
接口有默认的实现类SimpleJpaRepository
。(其实还有个QueryDslJpaRepository
扩展了SimpleJpaRepository
,暂忽略不计)
该类实现了JpaRepository
和JpaSpecificationExecutor
两个接口。它为我们提供了常用的几个仓库接口(JpaRepository
, PagingAndSortingRepository
, CrudRepository
)内各个方法的默认实现方式。
那么问题来了,如果我使用了仓库中的方法名查询推导(Query Derivation from method names),那么这样一个没有实现的接口中的抽象方法又是怎么正确运作的呢?
一个方法名查询推导(Query Derivation)示例:
这个接口中的findByEmailAndLastname
方法没有任何实现,但却能正确完成任务,这是怎么做到的呢?
从FactoryBean到Repository
从@EnableJpaRepositories
注解中可以看到,注解会默认注册JpaRepositoryFactoryBean.class
作为Repository仓库的工厂Bean。找到了Repository仓库的工厂Bean,应该很方便就能找到当中缺失的一环了。
从JpaRepositoryFactoryBean
的源码中可以看到它的继承结构:
JpaRepositoryFactoryBean
extends TransactionalRepositoryFactoryBeanSupport
TransactionalRepositoryFactoryBeanSupport
extends RepositoryFactoryBeanSupport
后两者来自于spring-data-commons项目。
FactoryBean.getObject()
方法由RepositoryFactoryBeanSupport
类实现,调用了RepositoryFactoryBeanSupport.initAndReturn()
方法,在该方法中可以看到调用了this.factory.getRepository(...)
方法来初始化仓库并将其保持在域中。那么问题来了,this.factory
从哪里来的呢?
在RepositoryFactoryBeanSupport
中搜索factory
就会看到,原来this.factory
是在afterPropertiesSet()
方法中,由抽象方法createRepositoryFactory()
提供的。
在TransactionalRepositoryFactoryBeanSupport
中可以看到,createRepositoryFactory()
方法被实现并被标记为final
。从实现中可以看到它又调用了抽象方法doCreateRepositoryFactory()
来获取RepositoryFactorySuport
,然后为该factory增加了exceptionPostProcessor
和txPostProcessor
两个PostProcessor。从名称上可以获悉这两个PostProcessor分别负责转换例外(将JPA例外转换成Spring专有的)和事务管理。
在JpaRepositoryFactoryBean
中可以看到,doCreateRepositoryFactory
方法被实现。该方法使用注入的EntityManager
来new了一个JpaRepositoryFactory
,没错,这个类和前面一个比少了一个Bean。
JpaRepositoryFactory
这个没有Bean的工厂类继承了RepositoryFactorySupport
类(在spring-data-commons项目中),和JpaRepositoryFactoryBean
的继承结构如出一辙。在RepositoryFactorySupport
这个类的源代码中,我们可以找到getRepository
方法的实现。
没错,关键缺失的一环就在这里。在这个方法中可以看到,首先它获取了Repository的各种信息,包括metadata、customImplementation、information等,
然后使用了ProxyFactory
,并且为这个ProxyFactory
注册了几个Advice
,最后通过getProxy
方法创建了一个Repository的代理。
而真正起到魔法般作用的应该就是这个QueryExecutorMethodInterceptor
类了。
从魔法到现实
然而我并不想去读懂这个QueryExecutorMethodInterceptor
,啥时候等我有空了看懂了再来说说这货的实现原理吧。
债见。