我已经在我的项目中使用Spring Data JPA存储库一段时间了,我知道以下几点:
-
在存储库接口中,我们可以添加类似
findByCustomerNameAndPhone()
的方法(假设customerName
和phone
是域对象中的字段) . -
然后,Spring通过在运行时(在应用程序运行期间)实现上述存储库接口方法来提供实现 .
我感兴趣的是如何编码它,我看了Spring JPA源代码和API,但我找不到下面问题的答案:
-
如何在运行时和方法中生成并注入存储库实现类?
-
Spring Data JPA是否使用CGlib或任何字节码操作库来实现方法并动态注入?
您能否帮助解决上述问题并提供任何支持的文档?
1 回答
首先,有's no code generation going on, which means: no CGLib, no byte-code generation at all. The fundamental approach is that a JDK proxy instance is created programmatically using Spring' s
ProxyFactory
API来支持接口,MethodInterceptor
拦截对实例的所有调用,并将方法路由到适当的位置:如果已使用自定义实现部件初始化存储库(有关详细信息,请参阅that part of the reference documentation),并且在该类中实现调用的方法,则会在此处路由调用 .
如果方法是查询方法(请参阅DefaultRepositoryInformation了解如何确定),则特定于商店的查询执行机制将启动并执行确定在启动时为该方法执行的查询 . 为此,尝试在各个地方(使用方法上的
@Query
,命名为JPA的查询)识别显式声明的查询,最终回退到方法名称的查询派生 . 有关查询机制检测,请参阅JpaQueryLookupStrategy . 可以在PartTree中找到查询派生的解析逻辑 . 可以看到商店特定的翻译成实际查询,例如,在JpaQueryCreator .如果以上都不适用,则执行的方法必须是由特定于商店的存储库基类实现的(在JPA的情况下为SimpleJpaRepository),并且将调用路由到该实例中 .
实现该路由逻辑的方法拦截器是
QueryExecutorMethodInterceptor
,可以找到高级路由逻辑here .这些代理的创建被封装到基于标准Java的Factory模式实现中 . 可以在RepositoryFactorySupport中找到高级代理创建 . 特定于商店的实现然后添加必要的基础架构组件,以便JPA可以继续编写如下代码:
我明确提到的原因是,应该清楚的是,在其核心中,该代码中没有任何东西需要Spring容器才能首先运行 . 它需要Spring作为类路径上的库(因为我们不喜欢重新发明轮子),但通常是容器不可知的 .
为了简化与DI容器的集成,我们当然会构建与Spring Java配置,XML命名空间以及CDI extension的集成,以便Spring Data可以用于普通的CDI场景 .