免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2745 | 回复: 0
打印 上一主题 下一主题

spring-data-jpa原理探秘-运行环境创建及加载Repository接口 [复制链接]

论坛徽章:
1
15-16赛季CBA联赛之同曦
日期:2017-01-17 18:19:30
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2017-02-13 11:24 |只看该作者 |倒序浏览

spring-data-jpa的优点很多,比如继承Repository接口,在注解中书写JPQL语句即可访问数据库;支持方法名解析方式访问数据库;使用Predicate支持动态查询等,在此不一一列举了。这些都是使用spring-data-jpa中的种种优点,要想将之使用的更好更优雅,就要从spring-data-jpa的加载和运行机制进行探秘。
此文系作者查看spring-data-jpa源码及参考javadoc文档成文,所以文中难免会有错误和纰漏,恳请读者指出。下面进入正题。

1.运行环境创建及加载Repository接口
spring-data-jpa在运行时和springframework框架实现了无缝对接。在使用spring的@Repository注解生成Repository实例时,使用动态代理类的方式对Repository接口进行了实例化并放入spring容器中备用。
下面是spring-data-jpa中占重要地位的RepositoryFactoryBeanSupport和RepositoryFactorySupport的类图:


RepositoryFactoryBeanSupport的作用是,为spring的FactoryBean接口开发的适配器,可以很便捷的通过spring配置设置repository工厂;而RepositoryFactorySupport的作用是,创建一个给定repository接口实例的工厂bean。创建一个实现配置的repository接口的代理,并应用一个advice将控制交给QueryExecuterMethodInterceptor。

通过查看源码,我们可以看到在RepositoryFactoryBeanSupport中持有一个私有RepositoryFactorySupport类变量,在执行RepositoryFactoryBeanSupport.afterPropertiesSet()方法时,通过createRepositoryFactory()方法,new了一个JpaRepositoryFactory实例并赋值给了类变量factory(RepositoryFactorySupport),查看JpaRepositoryFactory的构造器,可以看到持有了entityManager等实例,以方便后面的使用。RepositoryFactoryBeanSupport中的private T initAndReturn()是另一个相当重要的方法,方法说明是:
Returns the previously initialized repository proxy or creates and returns the proxy if previously uninitialized.返回先前实例化了的repository代理实例,或者,如果先前没有实例化,那么生成并且返回一个代理实例。
为什么这么说明呢?我们来看代码,这个方法被另外两个方法调用,一个是afterPropertiesSet(),这是实现InitialingBean接口需要实现的一个加载方法,一般会先调用;另一个则是实现FactoryBean接口需要实现的getObject()方法,在运行中会调用之返回一个Repository接口的实例。所以,一般来说initAndReturn()至少会有两次被调用的机会。initAndReturn()的实现比较简单:

private T initAndReturn() {    Assert.notNull(repositoryInterface, "Repository interface must not be null on initialization!");    if (this.repository == null) {        this.repository = this.factory.getRepository(repositoryInterface, customImplementation);    }    return this.repository;}

通过RepositoryFactorySupport(JpaRepositoryFactory实例)的getRepository(repositoryInterface, customImplementation);获取了一个org.springframework.data.jpa.repository.support.SimpleJpaRepository代理类实例(定义为泛型T extends Repository),在构造这个实例时,进行了一系列的运行环境准备:
在RepositoryFactorySupport的内部类QueryExecutorMethodInterceptor中获取Query查找策略类QueryLookupStrategy实例(此处一般是CreateIfNotFoundQueryLookupStrategy实例),然后执行resolveQuery(method, repositoryInformation, factory, namedQueries);方法将RepositoryQuery实例执行循环放入RepositoryFactorySupport(JpaRepositoryFactory实例)的类变量queries,一个ConcurrentHashMap<Method, RepositoryQuery>中。
下图是QueryLookupStrategy的类图:

构造RepositoryQuery实例时对应了一个JpaQueryMethod实例,RepositoryQuery实例实际上是SimpleJpaQuery实例。

上面的描述总括上来说,就是一个通过spring框架生成(注意不是注入生成)的JpaRepositoryFactoryBean实例实现了InitialzingBean接口,在public void afterPropertiesSet()方法调用时生成了一个SimpleJpaRepository代理实例。SimpleJpaRepository实例中持有本次实例化的Repository代理类,以及在QueryExecutorMethodInterceptor构造器中实例化了的多个JpaQueryMethod,顾名思义,JpaQueryMethod就是jpa的带有@Query注解的方法数据存储类,所以Repository接口有多少个方法,就会包含多少个JpaQueryMethod实例被加入监听序列。

参考文章:http://www.roncoo.com/article/index

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP