?Spring Data JPA系列
1、SpringBoot集成JPA及基本使用
2、Spring Data JPA Criteria查詢、部分字段查詢
3、Spring Data JPA數據批量插入、批量更新真的用對了嗎
4、Spring Data JPA的一對一、LazyInitializationException異常、一對多、多對多操作
5、Spring Data JPA自定義Id生成策略、復合主鍵配置、Auditing使用
6、【源碼】Spring Data JPA原理解析之Repository的自動注入(一)
7、【源碼】Spring Data JPA原理解析之Repository的自動注入(二)
8、【源碼】Spring Data JPA原理解析之Repository執行過程及SimpleJpaRepository源碼
9、【源碼】Spring Data JPA原理解析之Repository自定義方法命名規則執行原理(一)
10、【源碼】Spring Data JPA原理解析之Repository自定義方法命名規則執行原理(二)
11、【源碼】Spring Data JPA原理解析之Repository自定義方法添加@Query注解的執行原理
前言
上一篇限于篇幅,只分享了Repository自定義方法命名規則的方法在QueryExecutorMethodInterceptor的構造方法中,通過查詢查找策略CreateIfNotFoundQueryLookupStrategy創建一個PartTreeJpaQuery對象。該對象解析方法名稱的關鍵字、查詢屬性、查詢關鍵字,封裝成PartTree。而后將Method和PartTreeJpaQuery組合存放在QueryExecutorMethodInterceptor的Map<Method, RepositoryQuery> queries中。
本篇繼續往下分享Repository自定義方法命名規則的方法是如何調用執行的。
方法調用攔截
【源碼】Spring Data JPA原理解析之Repository的自動注入(二)-CSDN博客
上面博文分享了Repository bean的創建。Respository的bean是一個通過ProxyFactory創建的動態代理對象,該代理對象添加了QueryExecutorMethodInterceptor攔截器。
【源碼】Spring Data JPA原理解析之Repository執行過程及SimpleJpaRepository源碼-CSDN博客
博客中介紹了動態代理攔截,當Repository中的接口被調用的時候,會執行ReflectiveMethodInvocation.proceed()的方法,在該方法中,循環遍歷所有的攔截器,執行攔截器的invoke(MethodInvocation invocation)方法。
所以會執行QueryExecutorMethodInterceptor.invoke()方法。QueryExecutorMethodInterceptor的相關代碼如下:
package org.springframework.data.repository.core.support;/*** 此MethodInterceptor攔截對自定義實現的方法的調用,當自定義的方法被調用時,會被該類攔截。* 此外,它還解析對finder的方法調用,并觸發它們的執行。如果返回true,則可以依賴于設置自定義存儲庫實現實例。*/
class QueryExecutorMethodInterceptor implements MethodInterceptor {// Repository信息,為DefaultRepositoryInformation對象。獲取Repository信息,getRepositoryInformation()返回一個RepositoryInformation對象。// 如子類JpaRepositoryFactory,指定baseClass為SimpleJpaRepository.classprivate final RepositoryInformation repositoryInformation;// 方法緩存,key為方法,value為對應方法的查詢解析信息private final Map<Method, RepositoryQuery> queries;// 方法調用緩存,key為方法,value為對應方法調用時要執行的執行器private final Map<Method, RepositoryMethodInvoker> invocationMetadataCache = new ConcurrentReferenceHashMap<>();// 查詢執行結果處理器private final QueryExecutionResultHandler resultHandler;// 在實體類中添加@NamedQueries注解,配置相關查詢信息,默認為空private final NamedQueries namedQueries;private final List<QueryCreationListener<?>> queryPostProcessors;private final RepositoryInvocationMulticaster invocationMulticaster;// 省略其他@Override@Nullablepublic Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();// 通過返回的返回值,獲取執行適配器,默認都為nullQueryExecutionConverters.ExecutionAdapter executionAdapter = QueryExecutionConverters //.getExecutionAdapter(method.getReturnType());if (executionAdapter == null) {return resultHandler.postProcessInvocationResult(doInvoke(invocation), method);}return executionAdapter //.apply(() -> resultHandler.postProcessInvocationResult(doInvoke(invocation), method));}@Nullableprivate Object doInvoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();// 判斷方法是否存在RepositoryQuery。在構造函數中,會解析Repository中的查詢方法,并緩存到Mapif (hasQueryFor(method)) {RepositoryMethodInvoker invocationMetadata = invocationMetadataCache.get(method);if (invocationMetadata == null) {// 首次執行對應方法,先創建一個RepositoryQueryMethodInvoker對象,保存方法即方法對應的RepositoryQueryinvocationMetadata = RepositoryMethodInvoker.forRepositoryQuery(method, queries.get(method));// 加入緩存invocationMetadataCache.put(method, invocationMetadata);}// 獲取方法所在的Repository類名、方法的參數值【invocation.getArguments()】,執行RepositoryQueryMethodInvoker.invoke()方法return invocationMetadata.invoke(repositoryInformation.getRepositoryInterface(), invocationMulticaster,invocation.getArguments());}// 如果能夠處理該查詢方法,則不執行invocation.proceed(),即結束攔截器鏈return invocation.proceed();}/*** 判斷是否為給定方法執行查詢*/private boolean hasQueryFor(Method method) {return queries.containsKey(method);}}
1.1 在QueryExecutorMethodInterceptor.invoke()中,核心功能如下:
1)執行doInvoke()方法,執行數據庫相關操作,獲取返回信息;
2)執行resultHandler.postProcessInvocationResult(),進行返回值類型轉換;
1.2 在doInvoke()方法中,執行如下:
1)調用hasQueryFor()方法,判斷當前方法是否有對應的RepositoryQuery對象。在上一篇博文中以及做了詳細介紹,該對象是在QueryExecutorMethodInterceptor的構造方法中解析方法信息后封裝的和查詢相關的信息對象;
2)如果存在RepositoryQuery對象,則執行RepositoryMethodInvoker.forRepositoryQuery(method, queries.get(method)),創建一個RepositoryQueryMethodInvoker對象,然后執行RepositoryQueryMethodInvoker.invoke()方法;
3)如果不存在RepositoryQuery對象,則執行invocation.proceed(),執行ReflectiveMethodInvocation.proceed()方法,繼續執行下一個攔截器或執行target的對應方法;
RepositoryQueryMethodInvoker
RepositoryQueryMethodInvoker查詢方法回調類的核心代碼如下:
abstract class RepositoryMethodInvoker {private final Method method;private final Class<?> returnedType;private final Invokable invokable;private final boolean suspendedDeclaredMethod;@SuppressWarnings("ReactiveStreamsUnusedPublisher")protected RepositoryMethodInvoker(Method method, Invokable invokable) {this.method = method;if (KotlinDetector.isKotlinReflectPresent()) {// 省略其他} else {this.suspendedDeclaredMethod = false;this.returnedType = method.getReturnType();this.invokable = invokable;}}static RepositoryQueryMethodInvoker forRepositoryQuery(Method declaredMethod, RepositoryQuery query) {return new RepositoryQueryMethodInvoker(declaredMethod, query);}@Nullablepublic Object invoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args)throws Exception {return doInvoke(repositoryInterface, multicaster, args);}@Nullableprivate Object doInvoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args)throws Exception {// 創建一個RepositoryMethodInvocationCaptor對象RepositoryMethodInvocationCaptor invocationResultCaptor = RepositoryMethodInvocationCaptor.captureInvocationOn(repositoryInterface);try {// 執行對應方法的RepositoryQuery的execute方法Object result = invokable.invoke(args);if (result != null && ReactiveWrappers.supports(result.getClass())) {return new ReactiveInvocationListenerDecorator().decorate(repositoryInterface, multicaster, args, result);}if (result instanceof Stream) {return ((Stream<?>) result).onClose(() -> multicaster.notifyListeners(method, args, computeInvocationResult(invocationResultCaptor.success())));}// 執行結果通知。回調RepositoryMethodInvocationListener.afterInvocation()multicaster.notifyListeners(method, args, computeInvocationResult(invocationResultCaptor.success()));return result;} catch (Exception e) {multicaster.notifyListeners(method, args, computeInvocationResult(invocationResultCaptor.error(e)));throw e;}}private RepositoryMethodInvocation computeInvocationResult(RepositoryMethodInvocationCaptor captured) {return new RepositoryMethodInvocation(captured.getRepositoryInterface(), method, captured.getCapturedResult(),captured.getDuration());}interface Invokable {@NullableObject invoke(Object[] args) throws Exception;}private static class RepositoryQueryMethodInvoker extends RepositoryMethodInvoker {public RepositoryQueryMethodInvoker(Method method, RepositoryQuery repositoryQuery) {// repositoryQuery::execute方法回調聲明作為參數賦值給invokable,當執行invokable.invoke()時,// 執行repositoryQuery.execute()方法super(method, repositoryQuery::execute);}}// 省略其他
}
RepositoryQueryMethodInvoker是私有靜態內部類,父類為RepositoryMethodInvoker。
在上面講解的1.2的2)中,通過RepositoryMethodInvoker.forRepositoryQuery(method, queries.get(method)),創建一個RepositoryQueryMethodInvoker對象,將repositoryQuery::execute方法回調聲明作為參數賦值給invokable。
當執行RepositoryQueryMethodInvoker.invoke()時,執行doInvoke()方法,該方法執行如下:
1)創建一個RepositoryMethodInvocationCaptor對象;
2)執行invokable.invoke(),即執行對應方法的RepositoryQuery的execute方法,執行數據庫操作;
RepositoryQuery.execute() -> AbstractJpaQuery.execute() -> AbstractJpaQuery.doExecute() -> JpaQueryExecution.execute() -> JpaQueryExecution.doExecute()。
3)執行結果通知。回調RepositoryMethodInvocationListener.afterInvocation();
4)返回2)中的返回值;
第2)中調用的JpaQueryExecution.doExecute()是一個抽象方法,實現類如下:
針對數據庫表操作后不同的返回值信息,使用不同的實現類,且實現類都是JpaQueryExecution的內部類。以下以SingleEntityExecution為例。
public abstract class JpaQueryExecution {static class SingleEntityExecution extends JpaQueryExecution {@Overrideprotected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {return query.createQuery(accessor).getSingleResult();}}
}
執行AbstractJpaQuery.createQuery(),獲取一個Query對象,最后調用Query.getSingleResult(),返回一個查詢執行結果。其他的實現類處理類似,只是最后調用Query的不同方法,從數據庫中查詢不同的結果值。
AbstractJpaQuery
AbstractJpaQuery的相關代碼如下:
/*** 記錄Repository中每個方法解析后的信息*/
public abstract class AbstractJpaQuery implements RepositoryQuery {private final JpaQueryMethod method;private final EntityManager em;private final JpaMetamodel metamodel;// 根據EntityManager,返回PersistenceProvider。PersistenceProvider是枚舉類型,有HIBERNATE、ECLIPSELINK、GENERIC_JPA。// 不同的PersistenceProvider,extractQueryString、getIdentifierFrom等方式不一樣private final PersistenceProvider provider;// 根據查詢方法的返回值,使用不同的執行器private final Lazy<JpaQueryExecution> execution;// 參數綁定器final Lazy<ParameterBinder> parameterBinder = Lazy.of(this::createBinder);@Nullable@Overridepublic Object execute(Object[] parameters) {return doExecute(getExecution(), parameters);}/*** 執行查詢* @param execution 執行器。主要根據方法的返回值確定的執行器* @param values 方法執行時的參數值* @return*/@Nullableprivate Object doExecute(JpaQueryExecution execution, Object[] values) {// 創建一個JpaParametersParameterAccessor對象,保存方法的參數信息及本次查詢的參數值JpaParametersParameterAccessor accessor = obtainParameterAccessor(values);// 執行數據庫查詢,獲取返回值Object result = execution.execute(this, accessor);ResultProcessor withDynamicProjection = method.getResultProcessor().withDynamicProjection(accessor);return withDynamicProjection.processResult(result, new TupleConverter(withDynamicProjection.getReturnedType()));}private JpaParametersParameterAccessor obtainParameterAccessor(Object[] values) {if (method.isNativeQuery() && PersistenceProvider.HIBERNATE.equals(provider)) {return new HibernateJpaParametersParameterAccessor(method.getParameters(), values, em);}return new JpaParametersParameterAccessor(method.getParameters(), values);}/*** 獲取方法對應的查詢執行器*/protected JpaQueryExecution getExecution() {// 獲取根據返回值確定的查詢的執行器JpaQueryExecution execution = this.execution.getNullable();if (execution != null) {return execution;}// 如果添加了@Modify注解,則返回if (method.isModifyingQuery()) {return new ModifyingExecution(method, em);}// 否則返回單個實體類的執行器return new SingleEntityExecution();}/*** 為query添加定義的查詢hint信息。方法中添加@QueryHints注解*/protected <T extends Query> T applyHints(T query, JpaQueryMethod method) {List<QueryHint> hints = method.getHints();if (!hints.isEmpty()) {for (QueryHint hint : hints) {applyQueryHint(query, hint);}}// Apply any meta-attributes that existif (method.hasQueryMetaAttributes()) {if (provider.getCommentHintKey() != null) {query.setHint( //provider.getCommentHintKey(), provider.getCommentHintValue(method.getQueryMetaAttributes().getComment()));}}return query;}protected <T extends Query> void applyQueryHint(T query, QueryHint hint) {Assert.notNull(query, "Query must not be null");Assert.notNull(hint, "QueryHint must not be null");query.setHint(hint.name(), hint.value());}/*** 為query應用鎖模式*/private Query applyLockMode(Query query, JpaQueryMethod method) {LockModeType lockModeType = method.getLockModeType();return lockModeType == null ? query : query.setLockMode(lockModeType);}protected Query createQuery(JpaParametersParameterAccessor parameters) {return applyLockMode(applyEntityGraphConfiguration(applyHints(doCreateQuery(parameters), method), method), method);}/*** 如果方法添加@EntityGraph注解,在query中添加對應的Hint* @param query* @param method* @return*/private Query applyEntityGraphConfiguration(Query query, JpaQueryMethod method) {JpaEntityGraph entityGraph = method.getEntityGraph();if (entityGraph != null) {QueryHints hints = Jpa21Utils.getFetchGraphHint(em, method.getEntityGraph(),getQueryMethod().getEntityInformation().getJavaType());hints.forEach(query::setHint);}return query;}/*** 為查詢創建一個Query,并調用query.setParameter()設置參數值及分頁信息*/protected abstract Query doCreateQuery(JpaParametersParameterAccessor accessor);// 省略其他
}
在createQuery()方法中,執行如下:
1)調用抽象方法doCreateQuery(),獲取一個Query;
對于自定義方法命名規則的方法,實現在PartTreeJpaQuery類。
2)執行applyHints(),在query中添加對應的Hint;
3)執行applyEntityGraphConfiguration(),如果方法添加@EntityGraph注解,在query中添加對應的Hint;
4)執行applyLockMode(),為query應用鎖模式;
PartTreeJpaQuery
PartTreeJpaQuery的相關代碼如下:
package org.springframework.data.jpa.repository.query;/*** 保存了方法信息,包括方法、方法參數、方法名稱解析后的Part樹、對應的查詢query、查詢計數countQuery等信息*/
public class PartTreeJpaQuery extends AbstractJpaQuery {private final PartTree tree;private final JpaParameters parameters;private final QueryPreparer query;private final QueryPreparer countQuery;private final EntityManager em;private final EscapeCharacter escape;private final JpaMetamodelEntityInformation<?, Object> entityInformation;/*** 為查詢創建一個Query,并調用query.setParameter()設置參數值及分頁信息*/@Overridepublic Query doCreateQuery(JpaParametersParameterAccessor accessor) {return query.createQuery(accessor);}@Override@SuppressWarnings("unchecked")public TypedQuery<Long> doCreateCountQuery(JpaParametersParameterAccessor accessor) {return (TypedQuery<Long>) countQuery.createQuery(accessor);}private class QueryPreparer {// 緩存創建的對象private final @Nullable CriteriaQuery<?> cachedCriteriaQuery;private final @Nullable ParameterBinder cachedParameterBinder;private final QueryParameterSetter.QueryMetadataCache metadataCache = new QueryParameterSetter.QueryMetadataCache();QueryPreparer(boolean recreateQueries) {JpaQueryCreator creator = createCreator(null);if (recreateQueries) {this.cachedCriteriaQuery = null;this.cachedParameterBinder = null;} else {// 子類CountQueryPreparer的createQuery(),執行JpaCountQueryCreator重寫的complete()方法,// 執行query.select(),select為builder.count(),并加上predicate條件信息this.cachedCriteriaQuery = creator.createQuery();this.cachedParameterBinder = getBinder(creator.getParameterExpressions());}}/*** 為查詢創建一個Query,并調用query.setParameter()設置參數值及分頁信息*/public Query createQuery(JpaParametersParameterAccessor accessor) {CriteriaQuery<?> criteriaQuery = cachedCriteriaQuery;ParameterBinder parameterBinder = cachedParameterBinder;if (cachedCriteriaQuery == null || accessor.hasBindableNullValue()) {JpaQueryCreator creator = createCreator(accessor);criteriaQuery = creator.createQuery(getDynamicSort(accessor));List<ParameterMetadata<?>> expressions = creator.getParameterExpressions();parameterBinder = getBinder(expressions);}if (parameterBinder == null) {throw new IllegalStateException("ParameterBinder is null");}// 通過EntityManager.createQuery(criteriaQuery),返回TypedQueryTypedQuery<?> query = createQuery(criteriaQuery);ScrollPosition scrollPosition = accessor.getParameters().hasScrollPositionParameter()? accessor.getScrollPosition(): null;// 調用invokeBinding()執行query.setParameter()方法,設置查詢的條件參數值,如果有分頁,設置分頁信息// 如果有需要,設置返回最大值信息return restrictMaxResultsIfNecessary(invokeBinding(parameterBinder, query, accessor, this.metadataCache),scrollPosition);}@SuppressWarnings("ConstantConditions")private Query restrictMaxResultsIfNecessary(Query query, @Nullable ScrollPosition scrollPosition) {if (scrollPosition instanceof OffsetScrollPosition offset && !offset.isInitial()) {query.setFirstResult(Math.toIntExact(offset.getOffset()) + 1);}if (tree.isLimiting()) {if (query.getMaxResults() != Integer.MAX_VALUE) {if (query.getMaxResults() > tree.getMaxResults() && query.getFirstResult() > 0) {query.setFirstResult(query.getFirstResult() - (query.getMaxResults() - tree.getMaxResults()));}}query.setMaxResults(tree.getMaxResults());}if (tree.isExistsProjection()) {query.setMaxResults(1);}return query;}/*** 通過EntityManager.createQuery(criteriaQuery),返回TypedQuery*/private TypedQuery<?> createQuery(CriteriaQuery<?> criteriaQuery) {if (this.cachedCriteriaQuery != null) {synchronized (this.cachedCriteriaQuery) {return getEntityManager().createQuery(criteriaQuery);}}return getEntityManager().createQuery(criteriaQuery);}protected JpaQueryCreator createCreator(@Nullable JpaParametersParameterAccessor accessor) {EntityManager entityManager = getEntityManager();CriteriaBuilder builder = entityManager.getCriteriaBuilder();ResultProcessor processor = getQueryMethod().getResultProcessor();ParameterMetadataProvider provider;ReturnedType returnedType;if (accessor != null) {provider = new ParameterMetadataProvider(builder, accessor, escape);returnedType = processor.withDynamicProjection(accessor).getReturnedType();} else {provider = new ParameterMetadataProvider(builder, parameters, escape);returnedType = processor.getReturnedType();}if (accessor != null && accessor.getScrollPosition() instanceof KeysetScrollPosition keyset) {return new JpaKeysetScrollQueryCreator(tree, returnedType, builder, provider, entityInformation, keyset);}return new JpaQueryCreator(tree, returnedType, builder, provider);}/*** 調用query.setParameter()方法,設置查詢的條件參數值,如果有分頁,設置分頁信息*/protected Query invokeBinding(ParameterBinder binder, TypedQuery<?> query, JpaParametersParameterAccessor accessor,QueryParameterSetter.QueryMetadataCache metadataCache) {// 將query查詢添加到緩存QueryParameterSetter.QueryMetadata metadata = metadataCache.getMetadata("query", query);return binder.bindAndPrepare(query, metadata, accessor);}private ParameterBinder getBinder(List<ParameterMetadata<?>> expressions) {return ParameterBinderFactory.createCriteriaBinder(parameters, expressions);}private Sort getDynamicSort(JpaParametersParameterAccessor accessor) {return parameters.potentiallySortsDynamically() //? accessor.getSort() //: Sort.unsorted();}}private class CountQueryPreparer extends QueryPreparer {CountQueryPreparer(boolean recreateQueries) {super(recreateQueries);}/*** 創建一個JpaCountQueryCreator*/@Overrideprotected JpaQueryCreator createCreator(@Nullable JpaParametersParameterAccessor accessor) {EntityManager entityManager = getEntityManager();CriteriaBuilder builder = entityManager.getCriteriaBuilder();ParameterMetadataProvider provider;if (accessor != null) {provider = new ParameterMetadataProvider(builder, accessor, escape);} else {provider = new ParameterMetadataProvider(builder, parameters, escape);}return new JpaCountQueryCreator(tree, getQueryMethod().getResultProcessor().getReturnedType(), builder, provider);}@Overrideprotected Query invokeBinding(ParameterBinder binder, TypedQuery<?> query, JpaParametersParameterAccessor accessor,QueryParameterSetter.QueryMetadataCache metadataCache) {QueryParameterSetter.QueryMetadata metadata = metadataCache.getMetadata("countquery", query);return binder.bind(query, metadata, accessor);}}
}
1)在PartTreeJpaQuery.doCreateQuery()方法,執行QueryPreparer.createQuery()方法。
2)QueryPreparer.createQuery()方法先調用createQuery(),執行如下:
2.1)通過EntityManager.createQuery(criteriaQuery),返回TypedQuery;
2.2)執行invokeBinding(),在TypedQuery對象中,調用query.setParameter()綁定查詢條件的參數值,如果有分頁,設置分頁信息;
通過執行ParameterBinder.bindAndPrepare()方法,調用query.setParameter()綁定查詢條件的參數值,如果有分頁,設置分頁信息。
2.3)執行restrictMaxResultsIfNecessary(),如果有需要,設置返回最大值信息;
ParameterBinder
ParameterBinder的代碼如下:
package org.springframework.data.jpa.repository.query;/*** ParameterBinder用于將方法參數綁定到Query。通常在執行AbstractJpaQuery時執行。*/
public class ParameterBinder {static final String PARAMETER_NEEDS_TO_BE_NAMED = "For queries with named parameters you need to provide names for method parameters; Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters";private final JpaParameters parameters;// 查詢方法對應的參數設置器private final Iterable<QueryParameterSetter> parameterSetters;private final boolean useJpaForPaging;ParameterBinder(JpaParameters parameters, Iterable<QueryParameterSetter> parameterSetters) {this(parameters, parameterSetters, true);}public ParameterBinder(JpaParameters parameters, Iterable<QueryParameterSetter> parameterSetters,boolean useJpaForPaging) {Assert.notNull(parameters, "JpaParameters must not be null");Assert.notNull(parameterSetters, "Parameter setters must not be null");this.parameters = parameters;this.parameterSetters = parameterSetters;this.useJpaForPaging = useJpaForPaging;}public <T extends Query> T bind(T jpaQuery, QueryParameterSetter.QueryMetadata metadata,JpaParametersParameterAccessor accessor) {// 綁定參數值bind(metadata.withQuery(jpaQuery), accessor, ErrorHandling.STRICT);return jpaQuery;}public void bind(QueryParameterSetter.BindableQuery query, JpaParametersParameterAccessor accessor,ErrorHandling errorHandling) {// 遍歷方法的參數設置器,調用QueryParameterSetter.setParameter() -> query.setParameter()為查詢語句賦值for (QueryParameterSetter setter : parameterSetters) {setter.setParameter(query, accessor, errorHandling);}}Query bindAndPrepare(Query query, QueryParameterSetter.QueryMetadata metadata,JpaParametersParameterAccessor accessor) {// 綁定參數。調用query.setParameter(),為查詢賦值bind(query, metadata, accessor);// 如果沒有分頁,直接返回if (!useJpaForPaging || !parameters.hasLimitingParameters() || accessor.getPageable().isUnpaged()) {return query;}// 設置分頁信息query.setFirstResult(PageableUtils.getOffsetAsInteger(accessor.getPageable()));query.setMaxResults(accessor.getPageable().getPageSize());return query;}
}
小結
限于篇幅,本篇先分享到這里。結合上一篇【源碼】Spring Data JPA原理解析之Repository自定義方法命名規則執行原理(一)一起做一個小結:
1)Repository的代理類中,會添加QueryExecutorMethodInterceptor方法攔截器;
2)QueryExecutorMethodInterceptor方法攔截器的構造方法中,會根據查詢查找策略CreateIfNotFoundQueryLookupStrategy,獲得RepositoryQuery對象,解析方法。對于按方法命名規則實現的方法,使用的RepositoryQuery對象為PartTreeJpaQuery;
3)在PartTreeJpaQuery構造方法中,創建一個PartTree對象,解析方法名稱中的起始關鍵字【如:findBy、readBy、deleteBy等】、條件屬性【實體類中的屬性】、查詢關鍵字【Between、In、Equals等】;
4)創建對應方法的countQuery和query,將解析出的查詢的基礎信息封裝在QueryPreparer對象中,根據解析出的查詢信息,創建CriteriaQuery對象;
5)解析完方法信息,保存在PartTreeJpaQuery后,保存到QueryExecutorMethodInterceptor的Map<Method, RepositoryQuery> queries中;
6)當Repository的接口被調用的時候,在ReflectiveMethodInvocation.proceed()中,先執行QueryExecutorMethodInterceptor.invoke()方法;
6.1)調用doInvoke()方法,獲取數據庫執行后的數據;
6.1.1)調用RepositoryQueryMethodInvoker.invoke() -> RepositoryQuery.execute() -> AbstractJpaQuery.execute() -> AbstractJpaQuery.doExecute() -> JpaQueryExecution.execute() -> JpaQueryExecution.doExecute();
6.1.2)doExecute()是一個抽象方法,針對不同的數據庫查詢返回值信息,使用不同的實現類。所有的實現類都會先調用AbstractJpaQuery.createQuery(),獲取一個Query對象;
6.1.3)在AbstractJpaQuery.createQuery()中,調用抽象方法doCreateQuery()。對于按方法命名規則的Repository接口,實現類為PartTreeJpaQuery;
6.1.4)在PartTreeJpaQuery.coCreateQuery()方法中,通過EntityManager.createQuery(criteriaQuery)返回TypedQuery,然后執行invokeBinding(),在TypedQuery對象中,調用query.setParameter()綁定查詢條件的參數值,如果有分頁,設置分頁信息;
6.1.5)參數完參數,在6.1.3中設置hint等。然后執行6.1.2中的具體實現類,執行數據庫查詢。如SingleEntityExecution實現類,執行TypeQuery.getSingleResult(),然后單個結果;
6.2)調用resultHandler.postProcessInvocationResult(),對數據庫查詢后的值進行返回值類型轉換;
關于本篇內容你有什么自己的想法或獨到見解,歡迎在評論區一起交流探討下吧。