71 Spring 对于这部分 JpaRepository 的处理
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了71 Spring 对于这部分 JpaRepository 的处理相关的知识,希望对你有一定的参考价值。
前言
接上一篇 : JpaRepository 查询方法没有实现却可以正常使用
这是一个 我最开始看着 都挺奇怪的一个问题, 呵呵 存在一些 XXRepository的一些方法, 没有具体的方法实现, 但是 依然可以调用该方法 处理业务, 并且实现了 TaskCustomRepository 接口中的一部分自定义的接口
呵呵 比如 如下方法, 可以再业务代码中直接 @Resource 注入 TaskRepository, 然后也可以正常的调用他的 existsByTopic 方法, 但是 这个方法 却没有具体的实现, 一时之间很让人迷惑
TaskCustomRepository 这部分接口的行为 又是怎么约束的呢 ?
这一切的处理 Spring 又是怎么帮助我们处理的呢?
public interface TaskRepository extends JpaRepository<Task, String>, TaskCustomRepository
boolean existsByTopic(String topic);
关于 JpaRepositoriesAutoConfiguration
这部分的 TaskRepository 的实例来自于 JpaRepositoriesAutoConfiguration 的配置
来看一下 是什么加载了我们关注的这部分 Repository, 是 JpaRepositoriesAutoConfiguration @Import 的这个 JpaRepositoriesRegistrar 来处理的
extension 进行扫描寻找目标Repository, 可以看到看到这里 找到了 51 个 Repository, 然后依次 封装 BeanDefinition 注册到 registry
搜索一下我们系统里面的 继承自 AbstractRepository[继承了 JpaRepository] 的实现, 刚好是 51 个
extension 怎么加载的这部分目标 Repository
呵呵 我们上面 虽然看了一下 系统中继承自 AbstractRepository 的实现有 51 个 刚好对应上 上面的 extension 加载的目标 Repository 的数量, 但是 这个毕竟只是推测, 呵呵 我们还需要看下 extension 的加载规则, 来确认这个事情
extension 获取 candidates, 扫描的是配置的 basePackage 下面的所有的 class, filter 为 继承自 Repository 或者打上 @RepositoryDefinition 的并且没有打上 @NoRepositoryBean 的类型
basePackage 的值来自哪里 ?
basePackage 来自于 SpringBootApplication 的启动类的配置, 这里的 metadata wrap的为 SpringBoot 的启动类型
以为我们是没有配置 basePackage的, 所以我们看到的是一个默认的行为, 那么这个默认行为是什么呢? 启动类所在的 backage
之所以会走上面的配置 basePackage 的这些行为, 其最初还是来自于 ConfigClass 的处理
DcamsApplication 上面有 @SpringBootApplication, @SpringBootApplication 上面包含了 @EnableAutoConfiguration, @EnableAutoConfiguration 上面包含了 @AutoConfigurationPackage, @AutoConfigurationPackage 上面有一个 @Import(AutoConfigurationPackages.Registrar.class)
扫描 candidates, 注册到 registry
查询一下 Repository 的子类, 在 dcams 中其实也就那 51个 AbstractJpaRepository 的实现 + AbstractJpaRepository, AbstractJpaRepository 上面标记有 @NoRepositoryBean
scanner 合计扫描出来的 candidates 就是这 51个类型
拿到了这些东西之后, 上面一层 还有一层校验, 使用 ConfigurationInspectionClassLoader 加载 repositoryInterface, 以及下面的 isStrictRepositoryCandidate 的校验
我们来看一下 isStrictRepositoryCandidate, 是需要继承自 JpaRepository 或者打上 @Entity, @MappedSuperclass, 我们这里的 51个 candidates 显然都是满足条件的
我们再回到最上面 创建 BeanDefinition, 注册到 registry 的地方, 呵呵 看一下, 这里的 BeanDefinition 的 beanClassName 为 JpaRepositoryBean
我们这里 bean 明明是 taskRepostiroy 为什么 beanClassName 为 JpaRepositoryBean, 这个 JpaRepositoryBean 是从哪里配置进来的呢
呵呵来自于 EnableJpaRepositoriesConfiguration 上面的注解, EnableJpaRepositories 基本山都取得是默认值, beanClassName 为 JpaRepositoryBean
TaskRepository 的实例的创建
容器创建实例的时候发现一部分 Service 依赖于 TaskRepository, 因此开始创建 TaskRepository 的实例, 这里是根据 JpaRepositoryFactoryBean 来创建 TaskRepository 的实例
最终 TaskRepository 的实例的创建是在 RepositoryFactorySupport, 它相当于是 RepositoryFactoryBean 的 beanFactory, 用于最终创建实例
以上就是关于我们的这个 TaskRepository 实例是如何创建的整个流程了
关于 TaskCustomRepository
另外一点 我们关注的是 TaskCustomRepository, 从代码中可以直接看到的是 TaskRepository 实现了 TaskCustomRepository
那么业务代码中调用 TaskRepository 的 TaskCustomRepository 这部分的方法, 从我们的经验可以知道, 它是桥接到了 TaskCustomRepository 的具体实现, TaskRepositoryImpl, 他具体是怎么实现的呢?
我们出发一个 TaskCustomRepository 的方法的调用来看看, 看下下面这张图
最下面的是 业务代码 Service 里面调用 taskRepository.search, 经过了下面的 ImplementationMethodExecutionInterceptor 尝试在 repositoryComposition 中找到 search 方法的实现的对象
这里找到的是 TaskRepositoryImpl, 并且调用了 TaskRepositoryImpl 实例的 search 方法, 然后返回 业务数据
查询 TaskRepositoryImpl 是来自于 ImplementationMethodExecutionInterceptor 下面的 composite 下面的 fragments, 那么这个 fragments 又是来自于哪里呢?
再看 TaskRepository 的 BeanDefinition 的创建
RepositoryBeanDefinitionBuilder 构建 BeanDefinition 的时候, 获取了一部分的 customImplementation, 主要是通过 这里获取的
configuration.toLookupConfiguration 获取到一个 lookup, 表示的是具体的实现类, 查询一下 regsitry, 发现有这个 taskRepositoryImpl 的实现, 把他放到 beanDefinition 的 customImplementation 里面
我们再看看这个 lookup 的生成的方式
beanName 来自于拼接, 相当于是约定 xxRepository + 配置的后缀[默认为 Impl]
再看 TaskRepository 的实例的创建
呵呵 这里创建了一个 ImplementationMethodExecutionInterceptor, 传入的 composition 封装了 TaskRepositoryImpl 实例
我们上面看到的 fragments 来自于上一个层级的 JpaRepositoryFactoryBean 里面的 customImplementation, 自然也就来自于前面的 beanDefinition 的 customImplementation
完
以上是关于71 Spring 对于这部分 JpaRepository 的处理的主要内容,如果未能解决你的问题,请参考以下文章