我在项目中使用 Spring Data JPA 存储库已经有一段时间了,我知道以下几点:
- 在存储库接口中,我们可以添加类似的方法
findByCustomerNameAndPhone()
(假设customerName
and phone
是域对象中的字段)。
- 然后,Spring通过在运行时(应用程序运行期间)实现上述存储库接口方法来提供实现。
我对如何编码很感兴趣,并且查看了 Spring JPA 源代码和 API,但我找不到以下问题的答案:
- 运行时生成的存储库实现类以及如何实现和注入方法?
- Spring Data JPA 是否使用 CGlib 或任何字节码操作库来实现方法并动态注入?
您能否帮助解决上述问题并提供任何支持的文档?
首先,没有代码生成,这意味着:没有 CGLib,根本没有字节码生成。基本方法是使用 Spring 以编程方式创建 JDK 代理实例ProxyFactory
API 支持接口和MethodInterceptor
拦截对实例的所有调用并将方法路由到适当的位置:
- 如果存储库已使用自定义实现部分初始化(请参阅参考文档的那部分 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behaviour有关详细信息),并且调用的方法在该类中实现,调用将路由到该类。
- 如果该方法是查询方法(请参阅DefaultRepositoryInformation https://github.com/spring-projects/spring-data-commons/blob/1.12.2.RELEASE/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java#L163(了解如何确定),存储特定查询执行机制启动并执行确定在启动时为该方法执行的查询。为此,建立了一种解析机制,尝试识别在不同位置显式声明的查询(使用
@Query
在方法上,JPA 命名查询)最终回退到从方法名称派生查询。查询机制检测参见JpaQueryLookupStrategy https://github.com/spring-projects/spring-data-jpa/blob/1.10.2.RELEASE/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java#L181。查询派生的解析逻辑可以在PartTree https://github.com/spring-projects/spring-data-commons/blob/1.12.2.RELEASE/src/main/java/org/springframework/data/repository/query/parser/PartTree.java。可以看到商店特定的翻译为实际查询:在JpaQueryCreator https://github.com/spring-projects/spring-data-jpa/blob/1.10.2.RELEASE/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java#L214.
- 如果以上都不适用,则执行的方法必须是由特定于商店的存储库基类实现的方法(SimpleJpaRepository https://github.com/spring-projects/spring-data-jpa/blob/1.10.2.RELEASE/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L74如果是 JPA),并且调用将被路由到该实例的实例中。
实现该路由逻辑的方法拦截器是QueryExecutorMethodInterceptor
,可以找到高级路由逻辑here https://github.com/spring-projects/spring-data-commons/blob/1.12.2.RELEASE/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java#L470.
这些代理的创建被封装到基于标准 Java 的工厂模式实现中。高级代理创建可以在RepositoryFactorySupport https://github.com/spring-projects/spring-data-commons/blob/1.12.2.RELEASE/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java#L191。然后,特定于商店的实现添加必要的基础设施组件,以便对于 JPA,您可以继续编写如下代码:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
我明确提到这一点的原因是,应该清楚的是,从本质上讲,该代码的任何内容都不需要 Spring 容器来运行。它需要 Spring 作为类路径上的库(因为我们不喜欢重新发明轮子),但通常与容器无关。
为了简化与 DI 容器的集成,我们当然还构建了与 Spring Java 配置、XML 命名空间以及CDI 扩展 https://github.com/spring-projects/spring-data-jpa/tree/1.10.2.RELEASE/src/main/java/org/springframework/data/jpa/repository/cdi,这样Spring Data就可以用在普通的CDI场景中了。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)