首页 > 编程语言 >【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(一)

【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(一)

时间:2024-05-30 14:31:34浏览次数:26  
标签:return 自定义 private final public 源码 query 原理 method

  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自定义方法命名规则执行原理(一)

前言

在第一篇博文

SpringBoot集成JPA及基本使用-CSDN博客

中介绍了JPA的基本使用,在Repository接口中有三大类方法,分别为:

1)继承于JpaRepositoryImplementation接口,自动实现了CRUD等方法。

2)自定义接口方法,通过方法命名规则,无需写SQL或HQL,实现数据库表的操作。

3)自定义接口方法,通过@Query注解,添加SQL或HQL,实现数据库表的操作。

针对第一类,前一篇博文从源码的角度分享了自定义Repository实现JpaRepositoryImplementation接口后自动实现了CRUD等方法的实现原理。

【源码】Spring Data JPA原理解析之Repository的自动注入(二)

在上面这篇博文中分享了Repository bean的创建。Respository的bean是一个通过ProxyFactory创建的动态代理对象,该代理对象添加了QueryExecutorMethodInterceptor拦截器。Repository中的自定义接口方法都是在QueryExecutorMethodInterceptor中实现的。

QueryExecutorMethodInterceptor

QueryExecutorMethodInterceptor实现了MethodInterceptor,实现了方法拦截功能。在QueryExecutorMethodInterceptor的构造方法中,通过查询查找策略解析Repository中的自定义方法。QueryExecutorMethodInterceptor的代码如下:

package org.springframework.data.repository.core.support;


/**
 * 此MethodInterceptor拦截对自定义实现的方法的调用,当自定义的方法被调用时,会被该类拦截。
 * 此外,它还解析对finder的方法调用,并触发它们的执行。如果返回true,则可以依赖于设置自定义存储库实现实例。
 */
class QueryExecutorMethodInterceptor implements MethodInterceptor {

	// Repository信息,为DefaultRepositoryInformation对象。获取Repository信息,getRepositoryInformation()返回一个RepositoryInformation对象。
	// 如子类JpaRepositoryFactory,指定baseClass为SimpleJpaRepository.class
	private 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;

	/**
	 * Creates a new {@link QueryExecutorMethodInterceptor}. Builds a model of {@link QueryMethod}s to be invoked on
	 * execution of repository interface methods.
	 */
	public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformation,
			ProjectionFactory projectionFactory, Optional<QueryLookupStrategy> queryLookupStrategy, NamedQueries namedQueries,
			List<QueryCreationListener<?>> queryPostProcessors,
			List<RepositoryMethodInvocationListener> methodInvocationListeners) {

		this.repositoryInformation = repositoryInformation;
		// 需要在实体类中添加@NamedQueries注解,配置相关查询信息
		this.namedQueries = namedQueries;
		// 默认的监听器:RepositoryFactorySupport$QueryCollectingQueryCreationListener
		this.queryPostProcessors = queryPostProcessors;
		// methodInvocationListeners默认为空
		this.invocationMulticaster = methodInvocationListeners.isEmpty() ? NoOpRepositoryInvocationMulticaster.INSTANCE
				: new DefaultRepositoryInvocationMulticaster(methodInvocationListeners);
		// 查询执行结果处理器
		this.resultHandler = new QueryExecutionResultHandler(RepositoryFactorySupport.CONVERSION_SERVICE);

		if (!queryLookupStrategy.isPresent() && repositoryInformation.hasQueryMethods()) {

			throw new IllegalStateException(
					"You have defined query methods in the repository" + " but do not have any query lookup strategy defined."
							+ " The infrastructure apparently does not support query methods");
		}
		// queryLookupStrategy为JpaQueryLookupStrategy对象
		this.queries = queryLookupStrategy //
				.map(it -> mapMethodsToQuery(repositoryInformation, it, projectionFactory)) //
				.orElse(Collections.emptyMap());
	}

	private Map<Method, RepositoryQuery> mapMethodsToQuery(RepositoryInformation repositoryInformation,
			QueryLookupStrategy lookupStrategy, ProjectionFactory projectionFactory) {

		Map<Method, RepositoryQuery> result = new HashMap<>();
		// 遍历自定义Repository中定义的查询方法
		for (Method method : repositoryInformation.getQueryMethods()) {
			// 根据lookupStrategy(查找策略,JpaQueryLookupStrategy&CreateIfNotFoundQueryLookupStrategy对象)查询RepositoryQuery,并保存到Pair中
			Pair<Method, RepositoryQuery> pair = lookupQuery(method, repositoryInformation, lookupStrategy,
					projectionFactory);
			// 为RepositoryQuery添加监听
			invokeListeners(pair.getSecond());
			// 加入到Map中
			result.put(pair.getFirst(), pair.getSecond());
		}

		return result;
	}

	private Pair<Method, RepositoryQuery> lookupQuery(Method method, RepositoryInformation information,
			QueryLookupStrategy strategy, ProjectionFactory projectionFactory) {
		try {
			// 根据lookupStrategy(查找策略)查询RepositoryQuery
			return Pair.of(method, strategy.resolveQuery(method, information, projectionFactory, namedQueries));
		} catch (QueryCreationException e) {
			throw e;
		} catch (RuntimeException e) {
			throw QueryCreationException.create(e.getMessage(), e, information.getRepositoryInterface(), method);
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void invokeListeners(RepositoryQuery query) {

		// 默认的监听器:RepositoryFactorySupport$QueryCollectingQueryCreationListener
		for (QueryCreationListener listener : queryPostProcessors) {
			// 可解析类型
			ResolvableType typeArgument = ResolvableType.forClass(QueryCreationListener.class, listener.getClass())
					.getGeneric(0);

			if (typeArgument != null && typeArgument.isAssignableFrom(ResolvableType.forClass(query.getClass()))) {
				// RepositoryFactorySupport$QueryCollectingQueryCreationListener将查询对应的QueryMethod添加到集合中
				listener.onCreation(query);
			}
		}
	}

	@Override
	@Nullable
	public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable {

		Method method = invocation.getMethod();
		// 通过返回的返回值,获取执行适配器,默认都为null
		QueryExecutionConverters.ExecutionAdapter executionAdapter = QueryExecutionConverters //
				.getExecutionAdapter(method.getReturnType());

		if (executionAdapter == null) {
			return resultHandler.postProcessInvocationResult(doInvoke(invocation), method);
		}

		return executionAdapter //
				.apply(() -> resultHandler.postProcessInvocationResult(doInvoke(invocation), method));
	}

	@Nullable
	private Object doInvoke(MethodInvocation invocation) throws Throwable {

		Method method = invocation.getMethod();
		// 判断方法是否存在RepositoryQuery。在构造函数中,会解析Repository中的查询方法,并缓存到Map
		if (hasQueryFor(method)) {

			RepositoryMethodInvoker invocationMetadata = invocationMetadataCache.get(method);

			if (invocationMetadata == null) {
				// 首次执行对应方法,先创建一个RepositoryQueryMethodInvoker对象,保存方法即方法对应的RepositoryQuery
				invocationMetadata = 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);
	}

}

CreateIfNotFoundQueryLookupStrategy

在构造方法中,查询查找策略queryLookupStrategy是一个JpaQueryLookupStrategy.CreateIfNotFoundQueryLookupStrategy对象。

在Repository对应的BeanDefinitionBuilder.build()获取Repository的BeanDefinitionBuilder【用于创建BeanDefinition对象】时,会执行RepositoryConfiguration.getQueryLookupStrategyKey()方法,获取查找策略。默认的实现类DefaultRepositoryConfiguration.getQueryLookupStrategyKey()方法默认返回Key.CREATE_IF_NOT_FOUND。

在JpaRepositoryFactory.getRepository()时,调用getQueryLookupStrategy()方法,使用JpaQueryLookupStrategy.create()创建QueryLookupStrategy对象。返回CreateIfNotFoundQueryLookupStrategy。然后new QueryExecutorMethodInterceptor(),传入该查找策略

在loopupQuery()方法中,执行QueryLookupStrategy.resolveQuery(),即CreateIfNotFoundQueryLookupStrategy.resolveQuery(),解析方法,获得RepositoryQuery对象。

package org.springframework.data.jpa.repository.query;

/**
 * JPA的查询查找策略。
 * 在create()方法中,根据Key,创建一个QueryLookupStrategy,再通过QueryLookupStrategy,
 * 获取一个可以处理对应方法的RepositoryQuery。
 */
public final class JpaQueryLookupStrategy {

	private static final Log LOG = LogFactory.getLog(JpaQueryLookupStrategy.class);

	private static final RepositoryQuery NO_QUERY = new NoQuery();

	private JpaQueryLookupStrategy() {}

	/**
	 * 需要访问EntityManager的QueryLookupStrategy实现的基类
	 */
	private abstract static class AbstractQueryLookupStrategy implements QueryLookupStrategy {

		private final EntityManager em;
		// 用于创建对应查询方法的JpaQueryMethod对象
		private final JpaQueryMethodFactory queryMethodFactory;
		// 查询语句重写提供者。可以重新修改sql语句
		private final QueryRewriterProvider queryRewriterProvider;

		public AbstractQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
				QueryRewriterProvider queryRewriterProvider) {

			Assert.notNull(em, "EntityManager must not be null");
			Assert.notNull(queryMethodFactory, "JpaQueryMethodFactory must not be null");

			this.em = em;
			this.queryMethodFactory = queryMethodFactory;
			this.queryRewriterProvider = queryRewriterProvider;
		}

		@Override
		public final RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
				NamedQueries namedQueries) {
			// 先创建一个JpaQueryMethod
			JpaQueryMethod queryMethod = queryMethodFactory.build(method, metadata, factory);
			// 执行抽象方法,解析查询,获得一个RepositoryQuery
			return resolveQuery(queryMethod, queryRewriterProvider.getQueryRewriter(queryMethod), em, namedQueries);
		}

		protected abstract RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter queryRewriter,
				EntityManager em, NamedQueries namedQueries);

	}

	/**
	 * 返回一个PartTreeJpaQuery的RepositoryQuery对象
	 */
	private static class CreateQueryLookupStrategy extends AbstractQueryLookupStrategy {

		private final EscapeCharacter escape;

		public CreateQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
				QueryRewriterProvider queryRewriterProvider, EscapeCharacter escape) {

			super(em, queryMethodFactory, queryRewriterProvider);

			this.escape = escape;
		}

		@Override
		protected RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter queryRewriter, EntityManager em,
				NamedQueries namedQueries) {
			return new PartTreeJpaQuery(method, em, escape);
		}
	}

	/**
	 * 根据@Query中是否带nativeQuery属性值,返回NativeJpaQuery,或SimpleJpaQuery。如果没有配置value和name,则返回NamedQuery
	 */
	private static class DeclaredQueryLookupStrategy extends AbstractQueryLookupStrategy {

		// ExtensionAwareQueryMethodEvaluationContextProvider对象
		private final QueryMethodEvaluationContextProvider evaluationContextProvider;

		public DeclaredQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
				QueryMethodEvaluationContextProvider evaluationContextProvider, QueryRewriterProvider queryRewriterProvider) {

			super(em, queryMethodFactory, queryRewriterProvider);

			this.evaluationContextProvider = evaluationContextProvider;
		}

		@Override
		protected RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter queryRewriter, EntityManager em,
				NamedQueries namedQueries) {

			if (method.isProcedureQuery()) {
				return JpaQueryFactory.INSTANCE.fromProcedureAnnotation(method, em);
			}

			// 如果@Query设置了value属性值,即有数据库执行语句
			if (StringUtils.hasText(method.getAnnotatedQuery())) {

				if (method.hasAnnotatedQueryName()) {
					LOG.warn(String.format(
							"Query method %s is annotated with both, a query and a query name; Using the declared query", method));
				}
				// 如果方法的语句为native原生SQL,则创建NativeJpaQuery,否则创建SimpleJpaQuery
				// method.getRequiredAnnotatedQuery():获取@Query注解的value属性值,即查询语句
				return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, method.getRequiredAnnotatedQuery(),
						getCountQuery(method, namedQueries, em), queryRewriter, evaluationContextProvider);
			}

			// 获取@Query设置的name属性值
			String name = method.getNamedQueryName();
			// 包含在nameQueries中,如果方法的语句为native原生SQL,则创建NativeJpaQuery,否则创建SimpleJpaQuery
			if (namedQueries.hasQuery(name)) {
				return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, namedQueries.getQuery(name),
						getCountQuery(method, namedQueries, em), queryRewriter, evaluationContextProvider);
			}

			RepositoryQuery query = NamedQuery.lookupFrom(method, em);

			return query != null //
					? query //
					: NO_QUERY;
		}

		@Nullable
		private String getCountQuery(JpaQueryMethod method, NamedQueries namedQueries, EntityManager em) {
			// 如果方法的@Query添加了countQuery属性值,返回属性值
			if (StringUtils.hasText(method.getCountQuery())) {
				return method.getCountQuery();
			}
			// 获取queryName。因为没有添加countQuery属性,所以返回如:UserEntity.searchByName.count。searchByName为方法名称
			String queryName = method.getNamedCountQueryName();

			if (!StringUtils.hasText(queryName)) {
				return method.getCountQuery();
			}
			if (namedQueries.hasQuery(queryName)) {
				return namedQueries.getQuery(queryName);
			}

			// 是否通过@NamedQuires,尝试通过EntityManager.createNamedQuery()执行,不存在返回null
			boolean namedQuery = NamedQuery.hasNamedQuery(em, queryName);

			if (namedQuery) {
				return method.getQueryExtractor().extractQueryString(em.createNamedQuery(queryName));
			}

			return null;
		}
	}

	/**
	 * 先构造方法传入的DeclaredQueryLookupStrategy获取RepositoryQuery【详见DeclaredQueryLookupStrategy定义】,
	 * 如果没有找到,则使用构造方法传入的CreateQueryLookupStrategy获取PartTreeJpaQuery
	 */
	private static class CreateIfNotFoundQueryLookupStrategy extends AbstractQueryLookupStrategy {

		private final DeclaredQueryLookupStrategy lookupStrategy;
		private final CreateQueryLookupStrategy createStrategy;

		public CreateIfNotFoundQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
				CreateQueryLookupStrategy createStrategy, DeclaredQueryLookupStrategy lookupStrategy,
				QueryRewriterProvider queryRewriterProvider) {

			super(em, queryMethodFactory, queryRewriterProvider);

			Assert.notNull(createStrategy, "CreateQueryLookupStrategy must not be null");
			Assert.notNull(lookupStrategy, "DeclaredQueryLookupStrategy must not be null");

			this.createStrategy = createStrategy;
			this.lookupStrategy = lookupStrategy;
		}

		@Override
		protected RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter queryRewriter, EntityManager em,
				NamedQueries namedQueries) {

			// 先执行DeclaredQueryLookupStrategy的resolveQuery()
			RepositoryQuery lookupQuery = lookupStrategy.resolveQuery(method, queryRewriter, em, namedQueries);

			if (lookupQuery != NO_QUERY) {
				return lookupQuery;
			}
			// 没找到,执行CreateQueryLookupStrategy的resolveQuery()
			return createStrategy.resolveQuery(method, queryRewriter, em, namedQueries);
		}
	}

	/**
	 * 通过给定的EntityManager和Key,创建QueryLookupStrategy查询策略
	 */
	public static QueryLookupStrategy create(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
			@Nullable Key key, QueryMethodEvaluationContextProvider evaluationContextProvider,
			QueryRewriterProvider queryRewriterProvider, EscapeCharacter escape) {

		Assert.notNull(em, "EntityManager must not be null");
		Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null");

		switch (key != null ? key : Key.CREATE_IF_NOT_FOUND) {
			case CREATE:
				return new CreateQueryLookupStrategy(em, queryMethodFactory, queryRewriterProvider, escape);
			case USE_DECLARED_QUERY:
				return new DeclaredQueryLookupStrategy(em, queryMethodFactory, evaluationContextProvider,
						queryRewriterProvider);
			case CREATE_IF_NOT_FOUND:
				return new CreateIfNotFoundQueryLookupStrategy(em, queryMethodFactory,
						new CreateQueryLookupStrategy(em, queryMethodFactory, queryRewriterProvider, escape),
						new DeclaredQueryLookupStrategy(em, queryMethodFactory, evaluationContextProvider, queryRewriterProvider),
						queryRewriterProvider);
			default:
				throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s", key));
		}
	}

	/**
	 * 没有查询
	 */
	static class NoQuery implements RepositoryQuery {

		@Override
		public Object execute(Object[] parameters) {
			throw new IllegalStateException("NoQuery should not be executed!");
		}

		@Override
		public QueryMethod getQueryMethod() {
			throw new IllegalStateException("NoQuery does not have a QueryMethod!");
		}
	}
}

在CreateIfNotFoundQueryLookupStrategy.resolveQuery()方法中,执行如下:

1)先执行DeclaredQueryLookupStrategy的resolveQuery(),解析方法的@Query注解,根据注解的信息,如果是原生的,返回NativeJpaQuery;如果不是原生,返回SimpleJpaQuery;如果没有@Query注解,返回null;

2)如果1)中返回null,则执行CreateQueryLookupStrategy的resolveQuery(),new一个PartTreeJpaQuery对象,并返回该对象;

对于Repository方法命名规则实现的数据库表查询,因为没有添加@Query,所以返回的是PartTreeJpaQuery对象。获取的PartTreeJpaQuery对象和Method,添加到queries中进行缓存。

PartTreeJpaQuery

PartTreeJpaQuery保存了方法信息,包括方法、方法参数、方法名称解析后的Part树、对应的查询query、查询计数countQuery等信息,构造方法如下:

public class PartTreeJpaQuery extends AbstractJpaQuery {
    PartTreeJpaQuery(JpaQueryMethod method, EntityManager em, EscapeCharacter escape) {

		super(method, em);

		this.em = em;
		this.escape = escape;
		// 获取方法的参数,包括方法的实际参数,分页、排序在参数中的下标等
		this.parameters = method.getParameters();
		// 获取Repository<T, ID>中的T
		Class<?> domainClass = method.getEntityInformation().getJavaType();
		PersistenceUnitUtil persistenceUnitUtil = em.getEntityManagerFactory().getPersistenceUnitUtil();
		this.entityInformation = new JpaMetamodelEntityInformation<>(domainClass, em.getMetamodel(), persistenceUnitUtil);

		boolean recreationRequired = parameters.hasDynamicProjection() || parameters.potentiallySortsDynamically()
				|| method.isScrollQuery();

		try {
			// 解析方法名称。分解出名称中findBy、exist等关键字、属性、查询关键字【Like、In等】,根据Or分隔、再按And分隔
			this.tree = new PartTree(method.getName(), domainClass);
			validate(tree, parameters, method.toString());
			// 类JpaCountQueryCreator重写了complete()方法,执行query.select(),select为builder.count(),
			// 并加上predicate条件信息
			this.countQuery = new CountQueryPreparer(recreationRequired);
			// 如果是计算的查询,则query和countQuery一样
			this.query = tree.isCountProjection() ? countQuery : new QueryPreparer(recreationRequired);

		} catch (Exception o_O) {
			throw new IllegalArgumentException(
					String.format("Failed to create query for method %s; %s", method, o_O.getMessage()), o_O);
		}
	}

    // 省略其他

}

在构造方法中,完成如下:

1)创建一个PartTree,该对象解析方法名称,分解名称中的执行关键字【findBy、exist等】、属性、查询关键字【Like、In等】。先根据Or分隔,再根据And分隔;

2)创建对应方法的countQuery和query,将解析出的查询的基础信息封装在QueryPreparer对象中,根据解析出的查询信息,创建CriteriaQuery对象;

2.1 PartTree

PartTree的源码如下:

package org.springframework.data.repository.query.parser;

public class PartTree implements Streamable<OrPart> {

	private static final String KEYWORD_TEMPLATE = "(%s)(?=(\\p{Lu}|\\P{InBASIC_LATIN}))";
	private static final String QUERY_PATTERN = "find|read|get|query|search|stream";
	private static final String COUNT_PATTERN = "count";
	private static final String EXISTS_PATTERN = "exists";
	private static final String DELETE_PATTERN = "delete|remove";
	// ^(find|read|get|query|search|stream|count|exists|delete|remove)((\p{Lu}.*?))??By
	private static final Pattern PREFIX_TEMPLATE = Pattern.compile( //
			"^(" + QUERY_PATTERN + "|" + COUNT_PATTERN + "|" + EXISTS_PATTERN + "|" + DELETE_PATTERN + ")((\\p{Lu}.*?))??By");

	// 如"findDistinctUserByNameOrderByAge"方法名称,则subject为"DistinctUser"
	private final Subject subject;

	/**
	 * Predicate解析方法名中的属性信息、属性类型、关键字【Like、IN等】【先按Or分隔、再按And分隔】、排序信息。
	 * 如findDistinctUserByNameOrderByAge方法,则predicate包含name、orderByAge、name的属性等信息
 	 */

	private final Predicate predicate;

	/**
	 * @param source Repository中定义的方法的名称
	 * @param domainClass Repository<T, ID>中的T
	 */
	public PartTree(String source, Class<?> domainClass) {

		Assert.notNull(source, "Source must not be null");
		Assert.notNull(domainClass, "Domain class must not be null");

		// Kotlin name mangling, @JvmName cannot be used with interfaces
		// Kotlin名称篡改,@JvmName不能与接口一起使用
		int dash = source.indexOf('-');
		if (dash > -1) {
			source = source.substring(0, dash);
		}
		// ^(find|read|get|query|search|stream|count|exists|delete|remove)((\p{Lu}.*?))??By
		Matcher matcher = PREFIX_TEMPLATE.matcher(source);

		if (!matcher.find()) {
			this.subject = new Subject(Optional.empty());
			this.predicate = new Predicate(source, domainClass);
		} else {
			// 查找满足条件的字符串。如findBy、readBy等,创建一个Subject对象
			this.subject = new Subject(Optional.of(matcher.group(0)));
			// source.substring(matcher.group().length()):获取除findBy等名称中的其他字符串。如findByIdBetween,则为IdBetween
			// 创建Predicate,解析方法名中的谓词。解析属性部分(实体类中的属性)、排序部分
			this.predicate = new Predicate(source.substring(matcher.group().length()), domainClass);
		}
	}

	public Iterator<OrPart> iterator() {
		return predicate.iterator();
	}

	public Sort getSort() {
		return predicate.getOrderBySource().toSort();
	}

	public boolean isDistinct() {
		return subject.isDistinct();
	}

	public boolean isCountProjection() {
		return subject.isCountProjection();
	}

	/**
	 * 返回是否应用现有投影
	 */
	public boolean isExistsProjection() {
		return subject.isExistsProjection();
	}

	public boolean isDelete() {
		return subject.isDelete();
	}

	public boolean isLimiting() {
		return getMaxResults() != null;
	}

	@Nullable
	public Integer getMaxResults() {
		return subject.getMaxResults().orElse(null);
	}

	public Limit getResultLimit() {
		return subject.getMaxResults().map(Limit::of).orElse(Limit.unlimited());
	}

	public Streamable<Part> getParts() {
		return flatMap(OrPart::stream);
	}

	public Streamable<Part> getParts(Type type) {
		return getParts().filter(part -> part.getType().equals(type));
	}

	public boolean hasPredicate() {
		return predicate.iterator().hasNext();
	}

	@Override
	public String toString() {

		return String.format("%s %s", StringUtils.collectionToDelimitedString(predicate.nodes, " or "),
				predicate.getOrderBySource().toString()).trim();
	}

	/**
	 * 在给定的关键字keyword处拆分给定的文本text。期望驼峰格式大小写样式只匹配具体关键字,而不匹配其派生关键字。
	 */
	private static String[] split(String text, String keyword) {
		Pattern pattern = Pattern.compile(String.format(KEYWORD_TEMPLATE, keyword));
		return pattern.split(text);
	}

	/**
	 * 先按Or拆分,再按And拆分。OrPart存储了And的部分集合。如P1AndP2OrP3AndP4,则OrPart中的children为{P1、P2}或{P3、P4}
	 */
	public static class OrPart implements Streamable<Part> {

		private final List<Part> children;

		/**
		 * 先按Or拆分,再按And拆分
		 */
		OrPart(String source, Class<?> domainClass, boolean alwaysIgnoreCase) {
			// 按And拆分
			String[] split = split(source, "And");

			this.children = Arrays.stream(split)//
					.filter(StringUtils::hasText)//
					.map(part -> new Part(part, domainClass, alwaysIgnoreCase))//
					.collect(Collectors.toList());
		}

		public Iterator<Part> iterator() {
			return children.iterator();
		}

		@Override
		public String toString() {
			return StringUtils.collectionToDelimitedString(children, " and ");
		}
	}

	private static class Subject {

		private static final String DISTINCT = "Distinct";
		private static final Pattern COUNT_BY_TEMPLATE = Pattern.compile("^count(\\p{Lu}.*?)??By");
		private static final Pattern EXISTS_BY_TEMPLATE = Pattern.compile("^(" + EXISTS_PATTERN + ")(\\p{Lu}.*?)??By");
		private static final Pattern DELETE_BY_TEMPLATE = Pattern.compile("^(" + DELETE_PATTERN + ")(\\p{Lu}.*?)??By");
		private static final String LIMITING_QUERY_PATTERN = "(First|Top)(\\d*)?";
		// ^(find|read|get|query|search|stream)(Distinct)?(First|Top)(\d*)?(\p{Lu}.*?)??By
		private static final Pattern LIMITED_QUERY_TEMPLATE = Pattern
				.compile("^(" + QUERY_PATTERN + ")(" + DISTINCT + ")?" + LIMITING_QUERY_PATTERN + "(\\p{Lu}.*?)??By");

		private final boolean distinct;
		private final boolean count;
		private final boolean exists;
		private final boolean delete;
		private final Optional<Integer> maxResults;

		public Subject(Optional<String> subject) {
			// 判断是否包含Distinct、count、exists、delete、
			this.distinct = subject.map(it -> it.contains(DISTINCT)).orElse(false);
			this.count = matches(subject, COUNT_BY_TEMPLATE);
			this.exists = matches(subject, EXISTS_BY_TEMPLATE);
			this.delete = matches(subject, DELETE_BY_TEMPLATE);
			this.maxResults = returnMaxResultsIfFirstKSubjectOrNull(subject);
		}

		/**
		 * 返回第一个K主题为空时的最大结果
		 */
		private Optional<Integer> returnMaxResultsIfFirstKSubjectOrNull(Optional<String> subject) {

			return subject.map(it -> {

				// ^(find|read|get|query|search|stream)(Distinct)?(First|Top)(\d*)?(\p{Lu}.*?)??By
				Matcher grp = LIMITED_QUERY_TEMPLATE.matcher(it);
				// 传入findBy、countBy等,返回null
				if (!grp.find()) {
					return null;
				}

				return StringUtils.hasText(grp.group(4)) ? Integer.valueOf(grp.group(4)) : 1;
			});

		}

		public boolean isDelete() {
			return delete;
		}

		public boolean isCountProjection() {
			return count;
		}

		public boolean isExistsProjection() {
			return exists;
		}

		public boolean isDistinct() {
			return distinct;
		}

		public Optional<Integer> getMaxResults() {
			return maxResults;
		}

		private boolean matches(Optional<String> subject, Pattern pattern) {
			return subject.map(it -> pattern.matcher(it).find()).orElse(false);
		}
	}

	/**
	 * 解析方法名中的谓词。属性部分(实体类中的属性)、排序部分
	 */
	private static class Predicate implements Streamable<OrPart> {

		private static final Pattern ALL_IGNORE_CASE = Pattern.compile("AllIgnor(ing|e)Case");
		private static final String ORDER_BY = "OrderBy";
		// 保存方法名中的属性部分。即实体类中的属性
		private final List<OrPart> nodes;
		// 保存方法名中的排序部分
		private final OrderBySource orderBySource;
		private boolean alwaysIgnoreCase;

		public Predicate(String predicate, Class<?> domainClass) {
			// 按OrderBy拆分
			String[] parts = split(detectAndSetAllIgnoreCase(predicate), ORDER_BY);

			if (parts.length > 2) {
				throw new IllegalArgumentException("OrderBy must not be used more than once in a method name");
			}
			// 按Or切分,再按And切分。OrPart存储了And的部分集合。如P1AndP2OrP3AndP4,则OrPart中的children为{P1、P2}或{P3、P4}
			this.nodes = Arrays.stream(split(parts[0], "Or")) //
					.filter(StringUtils::hasText) //
					.map(part -> new OrPart(part, domainClass, alwaysIgnoreCase)) //
					.collect(Collectors.toList());
			// 排序部分
			this.orderBySource = parts.length == 2 ? new OrderBySource(parts[1], Optional.of(domainClass))
					: OrderBySource.EMPTY;
		}

		/**
		 * 检测并设置所有忽略大小写
		 * @param predicate 方法名中除findBy等开头的其他字符串信息
		 */
		private String detectAndSetAllIgnoreCase(String predicate) {

			// AllIgnor(ing|e)Case
			Matcher matcher = ALL_IGNORE_CASE.matcher(predicate);
			// 如果有包含,则删除对应字符串
			if (matcher.find()) {
				alwaysIgnoreCase = true;
				predicate = predicate.substring(0, matcher.start()) + predicate.substring(matcher.end(), predicate.length());
			}

			return predicate;
		}

		public OrderBySource getOrderBySource() {
			return orderBySource;
		}

		@Override
		public Iterator<OrPart> iterator() {
			return nodes.iterator();
		}
	}
}

在PartTree中,解析方法名称,分解出其中的subject以及predicate,即find、read等,以及属性、查询条件【Between、In等】、排序信息。其中的核心方法都做了注释。

2.2 QueryPreparer

QueryPreparer是PartTreeJpaQuery的内部类,代码如下:

public class PartTreeJpaQuery extends AbstractJpaQuery {

	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),返回TypedQuery
			TypedQuery<?> 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
		 */
		@Override
		protected 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);
		}

		@Override
		protected Query invokeBinding(ParameterBinder binder, TypedQuery<?> query, JpaParametersParameterAccessor accessor,
				QueryParameterSetter.QueryMetadataCache metadataCache) {

			QueryParameterSetter.QueryMetadata metadata = metadataCache.getMetadata("countquery", query);

			return binder.bind(query, metadata, accessor);
		}
	}
}

在QueryPreparer的构造方法中,

1)执行createCreator()方法,创建一个JpaQueryCreator对象,如果是CountQueryPreparer,返回的是子类JpaCountQueryCreator对象;

2)调用JpaQueryCreator.createQuery,创建CriteriaQuery对象;

public abstract class AbstractQueryCreator<T, S> {

	private final Optional<ParameterAccessor> parameters;
	private final PartTree tree;

	public T createQuery() {
		return createQuery(parameters.map(ParameterAccessor::getSort) //
				.orElse(Sort.unsorted()));
	}

	public T createQuery(Sort dynamicSort) {
		Assert.notNull(dynamicSort, "DynamicSort must not be null");
		return complete(createCriteria(tree), tree.getSort().and(dynamicSort));
	}

	/**
	 * 构建实际查询逻辑。遍历{@link PartTree}并调用回调方法来委托实际的条件创建和连接。
	 */
	@Nullable
	private S createCriteria(PartTree tree) {

		S base = null;
		Iterator<Object> iterator = parameters.map(ParameterAccessor::iterator).orElse(Collections.emptyIterator());
		// 遍历Or部分
		for (PartTree.OrPart node : tree) {

			Iterator<Part> parts = node.iterator();

			if (!parts.hasNext()) {
				throw new IllegalStateException(String.format("No part found in PartTree %s", tree));
			}
			// 创建criteria对象,并根据属性中的查询关键字,执行CriteriaBuilder.between()、CriteriaBuilder.greaterThan()等
			S criteria = create(parts.next(), iterator);

			// 遍历or中的and
			while (parts.hasNext()) {
				criteria = and(parts.next(), criteria, iterator);
			}

			base = base == null ? criteria : or(base, criteria);
		}

		return base;
	}

	/**
	 * 创建criteria对象的新原子实例
	 */
	protected abstract S create(Part part, Iterator<Object> iterator);

	/**
	 * 完成CriteriaQuery的创建
	 */
    protected abstract T complete(@Nullable S criteria, Sort sort);

    // 省略其他
	
}

createQuery()方法代码如上所示,该方法执行如下:

2.1)执行createCriteria()方法,根据方法名称解析后的PartTree,即查询的属性、关键字,调用create()抽象方法,创建一个Criteria API的Predicate对象。Criteria查询可以看

Spring Data JPA Criteria查询、部分字段查询-CSDN博客

2.2)执行tree.getSort().and(dynamicSort),添加排序信息;

2.3)执行complete(),创建CriteriaQuery对象;

以上的create()以及complete()都是抽象方法,其实现在子类JpaQueryCreator。

2.2.1 JpaQueryCreator

JpaQueryCreator的核心代码如下:

public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extends Object>, Predicate> {

	private final CriteriaBuilder builder;
	private final Root<?> root;
	private final CriteriaQuery<? extends Object> query;
	private final ParameterMetadataProvider provider;
	private final ReturnedType returnedType;
	private final PartTree tree;
	private final EscapeCharacter escape;

	public JpaQueryCreator(PartTree tree, ReturnedType type, CriteriaBuilder builder,
			ParameterMetadataProvider provider) {

		super(tree);
		this.tree = tree;
		// 创建一个CriteriaQuery
		CriteriaQuery<?> criteriaQuery = createCriteriaQuery(builder, type);

		this.builder = builder;
		this.query = criteriaQuery.distinct(tree.isDistinct() && !tree.isCountProjection());
		// 设置root
		this.root = query.from(type.getDomainType());
		this.provider = provider;
		this.returnedType = type;
		this.escape = provider.getEscape();
	}

	protected CriteriaQuery<? extends Object> createCriteriaQuery(CriteriaBuilder builder, ReturnedType type) {

		Class<?> typeToRead = tree.isDelete() ? type.getDomainType() : type.getTypeToRead();

		return (typeToRead == null) || tree.isExistsProjection() //
				? builder.createTupleQuery() //
				: builder.createQuery(typeToRead);
	}

	@Override
	protected Predicate create(Part part, Iterator<Object> iterator) {
		return toPredicate(part, root);
	}

	@Override
	protected final CriteriaQuery<? extends Object> complete(Predicate predicate, Sort sort) {
		// 子类JpaCountQueryCreator重写了complete()方法,执行query.select(),select为builder.count(),
		// 并加上predicate条件信息
		return complete(predicate, sort, query, builder, root);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected CriteriaQuery<? extends Object> complete(@Nullable Predicate predicate, Sort sort,
			CriteriaQuery<? extends Object> query, CriteriaBuilder builder, Root<?> root) {

		// 判断是否需要自定义构造
		if (returnedType.needsCustomConstruction()) {

			Collection<String> requiredSelection = getRequiredSelection(sort, returnedType);
			List<Selection<?>> selections = new ArrayList<>();

			for (String property : requiredSelection) {

				PropertyPath path = PropertyPath.from(property, returnedType.getDomainType());
				selections.add(toExpressionRecursively(root, path, true).alias(property));
			}

			Class<?> typeToRead = returnedType.getReturnedType();

			query = typeToRead.isInterface() //
					? query.multiselect(selections) //
					: query.select((Selection) builder.construct(typeToRead, //
							selections.toArray(new Selection[0])));

		} else if (tree.isExistsProjection()) { // 是否应用现有投影

			if (root.getModel().hasSingleIdAttribute()) {

				SingularAttribute<?, ?> id = root.getModel().getId(root.getModel().getIdType().getJavaType());
				query = query.multiselect(root.get((SingularAttribute) id).alias(id.getName()));

			} else {

				query = query.multiselect(root.getModel().getIdClassAttributes().stream()//
						.map(it -> (Selection<?>) root.get((SingularAttribute) it).alias(it.getName()))
						.collect(Collectors.toList()));
			}

		} else {
			// 否则直接查询
			query = query.select((Root) root);
		}
		// 添加排序
		CriteriaQuery<? extends Object> select = query.orderBy(QueryUtils.toOrders(sort, root, builder));
		// 添加条件
		return predicate == null ? select : select.where(predicate);
	}

	/**
	 * 通过给定的Part【查询条件部分】创建Predicate对象
	 * @param part
	 * @param root
	 * @return
	 */
	private Predicate toPredicate(Part part, Root<?> root) {
		return new PredicateBuilder(part, root).build();
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private class PredicateBuilder {

		private final Part part;
		private final Root<?> root;

		public PredicateBuilder(Part part, Root<?> root) {

			Assert.notNull(part, "Part must not be null");
			Assert.notNull(root, "Root must not be null");
			this.part = part;
			this.root = root;
		}
		
		/**
		 * 基于Part创建JPA的Predicate对象
		 * @return
		 */
		public Predicate build() {
            // PropertyPath保存查询条件中的属性的信息,如名称、类型、对应实体类等
			PropertyPath property = part.getProperty();
			Type type = part.getType();

			switch (type) {
				case BETWEEN:
					ParameterMetadata<Comparable> first = provider.next(part);
					ParameterMetadata<Comparable> second = provider.next(part);
					return builder.between(getComparablePath(root, part), first.getExpression(), second.getExpression());
				case AFTER:
				case GREATER_THAN:
					return builder.greaterThan(getComparablePath(root, part),
							provider.next(part, Comparable.class).getExpression());
				case GREATER_THAN_EQUAL:
					return builder.greaterThanOrEqualTo(getComparablePath(root, part),
							provider.next(part, Comparable.class).getExpression());
				case BEFORE:
				case LESS_THAN:
					return builder.lessThan(getComparablePath(root, part), provider.next(part, Comparable.class).getExpression());
				case LESS_THAN_EQUAL:
					return builder.lessThanOrEqualTo(getComparablePath(root, part),
							provider.next(part, Comparable.class).getExpression());
				case IS_NULL:
					return getTypedPath(root, part).isNull();
				case IS_NOT_NULL:
					return getTypedPath(root, part).isNotNull();
				case NOT_IN:
					// cast required for eclipselink workaround, see DATAJPA-433
					return upperIfIgnoreCase(getTypedPath(root, part))
							.in((Expression<Collection<?>>) provider.next(part, Collection.class).getExpression()).not();
				case IN:
					// cast required for eclipselink workaround, see DATAJPA-433
					return upperIfIgnoreCase(getTypedPath(root, part))
							.in((Expression<Collection<?>>) provider.next(part, Collection.class).getExpression());
				case STARTING_WITH:
				case ENDING_WITH:
				case CONTAINING:
				case NOT_CONTAINING:

					if (property.getLeafProperty().isCollection()) {

						Expression<Collection<Object>> propertyExpression = traversePath(root, property);
						ParameterExpression<Object> parameterExpression = provider.next(part).getExpression();

						// Can't just call .not() in case of negation as EclipseLink chokes on that.
						return type.equals(NOT_CONTAINING) //
								? isNotMember(builder, parameterExpression, propertyExpression) //
								: isMember(builder, parameterExpression, propertyExpression);
					}

				case LIKE:
				case NOT_LIKE:
					Expression<String> stringPath = getTypedPath(root, part);
					Expression<String> propertyExpression = upperIfIgnoreCase(stringPath);
					Expression<String> parameterExpression = upperIfIgnoreCase(provider.next(part, String.class).getExpression());
					Predicate like = builder.like(propertyExpression, parameterExpression, escape.getEscapeCharacter());
					return type.equals(NOT_LIKE) || type.equals(NOT_CONTAINING) ? like.not() : like;
				case TRUE:
					Expression<Boolean> truePath = getTypedPath(root, part);
					return builder.isTrue(truePath);
				case FALSE:
					Expression<Boolean> falsePath = getTypedPath(root, part);
					return builder.isFalse(falsePath);
				case SIMPLE_PROPERTY:
					ParameterMetadata<Object> expression = provider.next(part);
					Expression<Object> path = getTypedPath(root, part);
					return expression.isIsNullParameter() ? path.isNull()
							: builder.equal(upperIfIgnoreCase(path), upperIfIgnoreCase(expression.getExpression()));
				case NEGATING_SIMPLE_PROPERTY:
					return builder.notEqual(upperIfIgnoreCase(getTypedPath(root, part)),
							upperIfIgnoreCase(provider.next(part).getExpression()));
				case IS_EMPTY:
				case IS_NOT_EMPTY:

					if (!property.getLeafProperty().isCollection()) {
						throw new IllegalArgumentException("IsEmpty / IsNotEmpty can only be used on collection properties");
					}

					Expression<Collection<Object>> collectionPath = traversePath(root, property);
					return type.equals(IS_NOT_EMPTY) ? builder.isNotEmpty(collectionPath) : builder.isEmpty(collectionPath);

				default:
					throw new IllegalArgumentException("Unsupported keyword " + type);
			}
		}

	}
	// 省略其他
}

a)在JpaQueryCreator的构造方法中,通过CriteriaBuilder创建了CriteriaQuery对象;

b)在create()实现方法中,最终执行了new PredicateBuilder(part, root).build()。在build()方法中,根据Part【包含查询条件属性、查询条件关键字】中的查询条件关键字,使用CriteriaBuilder创建对应的Predicate;

c)在complete()方法中,通过构造方法中创建的CriteriaQuery对象,执行CriteriaQuery.select(),添加查询的Root。添加排序信息,然后将b)中的Predicate作为CriteriaQuery的查询条件,返回CriteriaQuery对象;

对于complete()方法,子类JpaCountQueryCreator重写了该方法。

2.2.2 JpaCountQueryCreator

JpaCountQueryCreator的代码如下:

public class JpaCountQueryCreator extends JpaQueryCreator {

	private boolean distinct;

	public JpaCountQueryCreator(PartTree tree, ReturnedType type, CriteriaBuilder builder,
			ParameterMetadataProvider provider) {

		super(tree, type, builder, provider);

		this.distinct = tree.isDistinct();
	}

	@Override
	protected CriteriaQuery<? extends Object> createCriteriaQuery(CriteriaBuilder builder, ReturnedType type) {
		// 查询返回Long类型
		return builder.createQuery(Long.class);
	}

	/**
	 * 执行query.select(),select为builder.count(),并加上predicate条件信息
	 */
	@Override
	@SuppressWarnings("unchecked")
	protected CriteriaQuery<? extends Object> complete(@Nullable Predicate predicate, Sort sort,
			CriteriaQuery<? extends Object> query, CriteriaBuilder builder, Root<?> root) {

		CriteriaQuery<? extends Object> select = query.select(getCountQuery(query, builder, root));
		return predicate == null ? select : select.where(predicate);
	}

	/**
	 * 获取count表达式
	 */
	@SuppressWarnings("rawtypes")
	private Expression getCountQuery(CriteriaQuery<?> query, CriteriaBuilder builder, Root<?> root) {
		return distinct ? builder.countDistinct(root) : builder.count(root);
	}
}

JpaCountQueryCreator的代码比较简单,创建一个查询返回值为Long的CriteriaQuery对象。在complete()方法中,执行CriteriaBuilder.count()统计,以及添加Predicate作为查询条件。

在QueryExecutorMethodInterceptor的构造方法中,通过CreateIfNotFoundQueryLookupStrategy查找策略解析Repository的方法的信息后,封装在RepositoryQuery对象后,保存到Map<Method, RepositoryQuery> queries中。

小结

限于篇幅,本篇先分享到这里。以下做一个小结:

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中;

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

标签:return,自定义,private,final,public,源码,query,原理,method
From: https://blog.csdn.net/JingAi_jia917/article/details/139237128

相关文章

  • 校园台球厅人员与设备|基于SprinBoot+vue的校园台球厅人员与设备管理系统(源码+数据库
    校园台球厅人员与设备管理系统目录基于SprinBoot+vue的校园台球厅人员与设备管理系统一、前言二、系统设计三、系统功能设计 1系统功能模块2管理员功能模块3用户功能模块四、数据库设计 五、核心代码 六、论文参考七、最新计算机毕设选题推荐八、源码获取:......
  • 校友社交|基于SprinBoot+vue的校友社交系统(源码+数据库+文档)
    校友社交系统目录基于SprinBoot+vue的校友社交系统一、前言二、系统设计三、系统功能设计 1系统功能模块2后台功能模块5.2.1管理员功能模块5.2.2用户功能模块四、数据库设计 五、核心代码 六、论文参考七、最新计算机毕设选题推荐八、源码获取:博主介绍:✌️......
  • 大药房|基于SprinBoot+vue的大药房管理系统(源码+数据库+文档)
    大药房管理系统目录基于SprinBoot+vue的大药房管理系统一、前言二、系统设计三、系统功能设计 1系统功能模块2管理员功能模块四、数据库设计 五、核心代码 六、论文参考七、最新计算机毕设选题推荐八、源码获取:博主介绍:✌️大厂码农|毕设布道师,阿里云开发......
  • 网上书城|基于SprinBoot+vue的网上书城管理系统(源码+数据库+文档)
    网上书城管理系统目录基于SprinBoot+vue的网上书城管理系统一、前言二、系统设计三、系统功能设计 1系统功能模块2管理员功能模块3用户后台功能模块四、数据库设计 五、核心代码 六、论文参考七、最新计算机毕设选题推荐八、源码获取:博主介绍:✌️大厂码农|......
  • TabControl和TabItem的样式自定义:为什么要使用自定义模板?
    在WPF(WindowsPresentationFoundation)中,控件的外观和行为是通过控件模板(ControlTemplate)来定义的。TabControl和TabItem控件也不例外,它们的默认控件模板定义了这些控件的结构和视觉状态。在实际应用中,开发者可能会发现直接设置TabItem的某些属性(例如Background)时不会生效。这篇......
  • Java 五种内部类演示及底层原理详解
    内部类什么是内部类在A类的内部定义B类,B类就被称为内部类发动机类单独存在没有意义发动机为独立个体可以在外部其他类里创建内部类的对象去调用方法类的五大成员属性方法构造方法代码块内部类内部类的访问特点内部类可以直接访问外部类的成员,包括私有外部类要......
  • 【GoMaxAI】最新的AI创作系统源码包括ChatGPT网站H5系统源码和Midjourney-AI绘画系统
    一、系统前言GoMaxAI创作系统是基于ChatGPT开发的智能问答系统和Midjourney绘画系统,支持OpenAI-GPT全模型和国内AI全模型。针对源码系统的完美测试结果,你想了解如何搭建部署AI创作ChatGPT系统,我这里提供一个详细的图文教程。系统已支持GPTs、GPT语音对话、GPT-4模型、联网提......
  • 深入探索令牌桶限流的原理与实践
    在当今的互联网时代,随着用户数量和请求量的不断增加,系统的性能和稳定性面临着巨大的挑战。限流算法作为保障系统稳定性的重要手段之一,被广泛应用于各种服务和应用中。限流的核心目的是对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓......
  • delphi 三层源码框架
    一,框架简介1,本套源码主要是用来开发企业应用系统如:erp,mes,hrms,进销存等制造业内部应用系统;跟网上常见的delphi中间件相比,功能更丰富,开发便捷。若用来开发一些几千上万的高并发,垮平台,实时高效的系统,可能需要自己优化下代码。(交流微信173713873)2,此框架服务端没有使用任何第三......
  • 在联网linux中编译nginx源码迁移到离线linux使用指南
    nginx没有预先编译好的npm包,通常需要通过编译源代码得到执行文件,下面介绍如何操作:1.找一台联网的linux服务器,安装必要的编译工具和依赖项sudoyumgroupinstall"DevelopmentTools"sudoyuminstallpcre-develzlib-developenssl-devel2.下载nginx源代码包wgethttp:/......