前言
在使用spring-data-jpa
對于dao層或者叫做數(shù)據(jù)倉庫層,我們只需要定一個(gè)簡單的repository接口融击,就能完成一些基本的curd操作筑公。但本質(zhì)上spring幫我們做了很多事情。
學(xué)習(xí)spring-data-jpa原理的收益
- 有助于我們理解
spring-data-jpa
尊浪,使用起來更加得心應(yīng)手匣屡。 - 學(xué)習(xí)spring的設(shè)計(jì)模式涩拙,有助于日志業(yè)務(wù)中間件的開發(fā)。
EnableJpaRepositories
這是一個(gè)開啟Srping JPA的代碼配置的注解耸采。這個(gè)套路在spring里面已經(jīng)司空見慣兴泥。
常用屬性
-
basePackages
/basePackageClasses
指定掃描repository 的包路徑 -
repositoryBaseClass
指定repository的基類,默認(rèn)是SimpleJpaRepository
哦虾宇。
registerBeanDefinitions
打開注解 @EnableJpaRepositories
的源碼發(fā)現(xiàn)搓彻,它的核心是導(dǎo)入了一個(gè)JpaRepositoriesRegistrar
(jpa倉庫登記員)的類。
可以看出這個(gè)登記員的核心方法是
registerBeanDefinitions
嘱朽,我們在該方法里面設(shè)置一個(gè)斷點(diǎn)旭贬。看下方法的調(diào)用棧信息搪泳。
- 發(fā)生在
refreshContext
階段 - 使用的是
ConfigurationClassPostProcessor
進(jìn)行處理的稀轨。 - 通過
@Configuration
注解加載BeanDefinition
- 通過登記員加載
BeanDefinition
- 名叫
Jpa Repository
的登記員登記BeanDefinition
當(dāng)然實(shí)際的邏輯是它的支撐類在執(zhí)行。
找到了口子之后岸军,我們再來詳細(xì)地分析下registerBeanDefinitions的源代碼奋刽。由于貼圖比較占篇幅,這段過程就以文字描述為主了艰赞。請讀者對照下spring源碼佣谐。
-
首先有個(gè)最基礎(chǔ)的判斷,只有使用
EnableJpaRepositories
注解方妖,才會(huì)執(zhí)行注冊數(shù)據(jù)倉庫的邏輯狭魂。
image-20210501110028417 -
接著構(gòu)建一個(gè)數(shù)據(jù)倉庫配置代表
RepositoryConfigurationDelegate
構(gòu)建過程的關(guān)鍵信息就是填充了一個(gè)默認(rèn)數(shù)據(jù)倉庫配置類DefaultRepositoryConfiguration
,這個(gè)是類是每個(gè)repository一個(gè)党觅,找repository的方式很粗暴雌澄,image-20210501144755194 然后代表執(zhí)行
registerRepositoriesIn
將BeanDefinition
注冊到注冊中心。
delegate.registerRepositoriesIn(registry, extension);
- 方法內(nèi)部杯瞻,使用
RepositoryBeanDefinitionBuilder
依據(jù)DefaultRepositoryConfiguration
創(chuàng)建镐牺,注意此時(shí)創(chuàng)建的BeanDefinition
的beanClass是org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean
- 到此完成了repository的
BeanDefinition
的注冊。那啥時(shí)候創(chuàng)建repository的呢又兵。答案就藏在JpaRepositoryFactoryBean
的afterPropertiesSet
方法里任柜。同樣afterPropertiesSet
邏輯也是由支撐類RepositoryFactoryBeanSupport
(和JpaRepositoryFactoryBean
是父子關(guān)系)實(shí)現(xiàn)的卒废。
Create Repository
我們將斷點(diǎn)設(shè)置在這個(gè)方法里沛厨,來看下它的調(diào)用棧。- 仍然發(fā)生在刷新
ApplicationContext
中 - 初始化所有非懶加載的單例的Bean
- 實(shí)際交給Bean工廠執(zhí)行初始化單例模式的bean
- 初始化bean摔认,調(diào)用幾個(gè)和bean初始化相關(guān)的
有感知的方法
逆皮,調(diào)用初始化方法(afterPropertiesSet
和initMehod
) - 調(diào)用
afterPropertiesSet
RepositoryFactoryBeanSupport#afterPropertiesSet
首先創(chuàng)建了一個(gè)數(shù)據(jù)倉庫工廠(JpaRepositoryFactory)。然后調(diào)用工廠的getRepository
方法参袱,實(shí)際邏輯還是他的父類RepositoryFactorySupport
中电谣。最核心的是使用了spring aop的動(dòng)態(tài)代理生成了repository實(shí)例秽梅。注意JpaRepositoryFactory
的getRepositoryBaseClass
方法硬編碼為SimpleJpaRepository
,這個(gè)類實(shí)現(xiàn)了常見的CURD操作。
小結(jié)
整個(gè)過程下來剿牺。給我感受最深的就是spring代碼非常條理清楚企垦,有條不穩(wěn),層次分明
讀好的源碼就好像是在讀一篇有理有據(jù)的議論文晒来。這對我們在寫業(yè)務(wù)代碼是很有幫助的钞诡。由于本篇關(guān)注的是整個(gè)repository bean
的創(chuàng)建過程,所以其中很多地方都是一帶而過湃崩。比如spring aop的動(dòng)態(tài)代理禽绪,factory bean项钮, bean的初始化,都可以詳細(xì)展開。