spring-data-jpa原理探祕(1)-運行環境創建及加載Repository接口

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實例被加入監聽序列。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章