整体流程

创建过程:

  • Spring 刷新上下文 -> 实例化 Bean -> 调用初始化 Hook

    • 使用 JpaRepositoryFactoryBean 构建仓库工厂 Bean

      默认非 Lazy 启动模式下创建仓库实例 -> 创建代理工厂代理该实例 -> 代理工厂使用切面添加多个 Advice:比如方法调用校验器、接口默认方法拦截器、自定义方法实现拦截器、自定义接口实现拦截器

core-sequence-diagram

自定义方法实现拦截器

针对自定义方法实现拦截器:QueryExecutorMethodInterceptor

在创建该拦截器时,会使用 Query Lookup Strategy 来查找合适的查询实现,查询实现负责基于该方法使用其参数查询并返回结果,该策略默认值为 CREATE_IF_NOT_FOUND,会先去找定义的查询:比如先使用基于 @Query 的注解来构建查询,如果不存在则使用 @Procedure 注解构建存储过程查询,最后再尝试查找命名查询,如果都不存在,则使用 PartTreeJpaQuery 构建基于方法名的查询。

PartTreeJpaQuery 将方法名根据前缀模版正则分隔成 主体-Subject谓词-Predicate 两部分,谓词又使用 Or 划分成多个 OrPartOrPart 又由 And 拆分为多个 PartPart 包含两部分:根据关键字判定为不同的查询条件的类型和该条件对应的实体属性,有了这些 Part 就可以用来构建 javax.criteria.Predicate 并最终构建出 javax.criteria.CriteriaQuery,这是 JAVAEE/Jakarta 的标准动态查询接口。

该拦截器被作为 Spring AOP 动态代理实现的仓库实例方法的切面通知(Advice)(由于我们是基于接口的代理,内部使用的是 JdkDynamicAopProxy),当我们调用仓库接口方法时,会通过 AOP 的调用链调用到我们的方法拦截器。