当前位置: 首页 > news >正文

【源码】Spring Data JPA原理解析之Repository执行过程及SimpleJpaRepository源码

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

前言

在前一篇文章

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

分享了Repository bean的创建。Respository的bean是一个通过ProxyFactory创建的动态代理对象,该代理对象实现了自定义的Repository接口、Repository.class以及TransactionProxy.class接口,且代理的target为SimpleJpaRepository对象。

在开发中,只需自定义实现JpaRepository接口,就可以实现CRUD、findBy+属性名称+条件查询等许多查询功能,核心在于使用了动态代理,其中的save、delete、find等功能的实现就在SimpleJpaRepository。

本篇分享一下SimpleJpaRepository的原理,在开始介绍之前,先了解一下动态代理是如何执行而后调用执行到SimpleJpaRepository。

动态代理方法拦截

Spring框架的两大核心概念:IOC(控制反转,把创建对象过程交给Spring进行管理)和AOP(面向切面,不修改源代码进行功能增强)。前面讲解的两篇Repository的自动注入使用的是Spring的IOC,而Repository的代理对象使用的是AOP。AOP是一种编程思想,是基于动态代理实现。

限于篇幅,此处只分享核心的实现。

Respository的bean是一个通过ProxyFactory创建的动态代理对象,ProxyFactory的父类的是ProxyCreatorSupport。在ProxyCreatorSupport的构造方法中,会new一个DefaultAopProxyFactory()。

2.1 DefaultAopProxyFactory

DefaultAopProxyFactory为默认的AOP代理创建工厂,代码如下:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {// config.isOptimize()与config.isProxyTargetClass()默认返回都是false,可以通过config进行配置修改// 需要优化 || 强制cglib || 没有实现接口if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}// 倘若目标Class本身就是个接口,或者它已经是个JDK的代理类(Proxy的子类。所有的JDK代理类都是此类的子类),// 用JDK的动态代理。Proxy.isProxyClass(targetClass)方法判断targetClass是否是Proxy通过// getProxyClass()或newProxyInstance()创建的if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}// 实用CGLIB代理方式// ObjenesisCglibAopProxy是CglibAopProxy的子类。Spring4.0之后提供的return new ObjenesisCglibAopProxy(config);}else {// 否则采用JDK得动态代理。(一般都有实现接口)return new JdkDynamicAopProxy(config);}}/*** 判断该代理对象是否没有用户提供的代理接口,是返回true* * 如果它没有实现过接口(ifcs.length == 0)||* 仅仅实现了一个接口,但是这个接口却是SpringProxy类型的。返回false* 其中SpringProxy:一个标记接口。Spring AOP产生的所有的代理类都是它的子类*/private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {Class<?>[] ifcs = config.getProxiedInterfaces();return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));}}

该类对外只有一个createAopProxy()方法,返回一个AopProxy。对于Repository,在创建ProxyFactory之后,调用setInterfaces(),添加实现的接口,所以上面的hasNoUserSuppliedProxyInterfaces()方法将返回false。所以createAopProxy()方法返回的是JdkDynamicAopProxy对象。

2.2 JdkDynamicAopProxy

JdkDynamicAopProxy的核心代码如下:

/*** 实现AopProxy和InvocationHandler,自己本身是代理回调的处理器*/
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {/*** 真正创建JDK动态代理实例*/@Overridepublic Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());}// 寻找接口,到最终代理的接口就是这里返回的所有接口(除了自己的接口,还有Spring默认的一些接口)Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);//查找被代理的接口中是否定义了equals、hashCode方法findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);// 第三个参数传的this,处理器就是自己,表示当前类是InvocationHandler类型的,当调用代理对象的任何方法的时候// 都会被被当前类的 invoke 方法处理。new一个代理对象return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}/*** 当在程序中调用代理对象的任何方法,最终都会被invoke方法处理*/@Override@Nullablepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//旧的代理对象Object oldProxy = null;//用来标记是否需要将代理对象暴露在ThreadLocal中boolean setProxyContext = false;//获取目标源TargetSource targetSource = this.advised.targetSource;//目标对象Object target = null;try {// 处理equals方法if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {return equals(args[0]);}// 处理hashCode方法else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {return hashCode();}/*** 处理DecoratingProxy*/else if (method.getDeclaringClass() == DecoratingProxy.class) {return AopProxyUtils.ultimateTargetClass(this.advised);}// 方法来源于 Advised 接口,代理对象默认情况下会实现 Advised 接口,可以通过代理对象来动态向代理对象中添加通知等else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}Object retVal;//是否需要在threadLocal中暴露代理对象if (this.advised.exposeProxy) {oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);// 获取当前方法的拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// 拦截器链为空的情况下,表示这个方法上面没有找到任何增强的通知,那么会直接通过反射调用目标对象if (chain.isEmpty()) {// 获取方法请求的参数(有时候方法中有可变参数,所谓可变参数就是带有省略号(...)这种格式的参数,// 传入的参数类型和这种类型不一样的时候,会通过下面的adaptArgumentsIfNecessary方法进行转换)Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);//通过反射直接调用目标方法retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {// 创建一个方法调用器(包含了代理对象、目标对象、调用的方法、参数、目标类型、方法拦截器链)MethodInvocation invocation =new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// 通过拦截器链一个个调用最终到目标方法的调用retVal = invocation.proceed();}// 根据方法返回值的类型,做一些处理,比如方法返回的类型为自己,则最后需要将返回值置为代理对象Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target &&returnType != Object.class && returnType.isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {retVal = proxy;}// 方法的返回值类型returnType为原始类型(即int、byte、double等这种类型的) && retVal为null,// 此时如果将null转换为原始类型会报错,所以此处直接抛出异常else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {// 目标对象不为null && 目标源不是静态的//所谓静态的,你可以理解为是否是单例的// isStatic为true,表示目标对象是单例的,同一个代理对象中所有方法共享一个目标对象// isStatic为false的时候,通常每次调用代理的方法,target对象是不一样的,所以方法调用万之后需要进行释放,可能有些资源清理,连接的关闭等操作if (target != null && !targetSource.isStatic()) {// Must have come from TargetSource.targetSource.releaseTarget(target);}if (setProxyContext) {// 需要将旧的代理再放回到上线文中AopContext.setCurrentProxy(oldProxy);}}}// 省略其他}

2.2.1 使用ProxyFactory.getProxy()方法时,会先createAopProxy(),调用2.1中的DefaultAopProxyFactory.createAopProxy()方法,返回一个JdkDynamicAopProxy对象,然后调用JdkDynamicAopProxy.getProxy()方法。在上面的getProxy()方法中,执行Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)创建一个代理对象,并返回。其中第三个参数为this,即JdkDynamicAopProxy本身,因为JdkDynamicAopProxy实现了InvocationHandler接口;

2.2.2 当代理对象的方法被调用的时候,都会执行InvocationHandler.invoke()方法。结合2.2.1的分析,会执行JdkDynamicAopProxy.invoke()方法。该方法的前半部分用于处理特殊方法,如equals、hashCode等。

然后获取当前方法的拦截器链,如果没有拦截器,则反射执行原方法;如果有,则new一个ReflectiveMethodInvocation对象,并调用ReflectiveMethodInvocation.proceed()方法。

对于Repository接口类,在创建的时候添加了好几个拦截器,所以会new一个ReflectiveMethodInvocation对象,并调用ReflectiveMethodInvocation.proceed()方法。

2.3 ReflectiveMethodInvocation

ReflectiveMethodInvocation的核心代码如下:

/*** Joinpoint的唯一实现子类,维护代理对象、目标对象、执行方法、方法可用的所有拦截器。在proceed()方法中,遍历所有可用的拦截器,* 并挨个匹配执行,如果不能匹配,则递归执行proceed()方法,执行下一个拦截器*/
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {//代理对象protected final Object proxy;//目标对象@Nullableprotected final Object target;//调用的方法protected final Method method;//调用方法的参数protected Object[] arguments;//目标类的class对象@Nullableprivate final Class<?> targetClass;/*** Lazily initialized map of user-specific attributes for this invocation.*/@Nullableprivate Map<String, Object> userAttributes;//需要动态核对的MethodInterceptor和InterceptorAndDynamicMethodMatcher列表protected final List<?> interceptorsAndDynamicMethodMatchers;// 当前使用的拦截器在集合中的下标private int currentInterceptorIndex = -1;/*** 保存基本信息*/protected ReflectiveMethodInvocation(Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {this.proxy = proxy;this.target = target;this.targetClass = targetClass;//获取桥接方法this.method = BridgeMethodResolver.findBridgedMethod(method);this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;}/*** 执行下一个拦截器* @return* @throws Throwable*/@Override@Nullablepublic Object proceed() throws Throwable {// We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {// 开始时,currentInterceptorIndex等于-1。当切面通知无法处理该代理方法时,会调用proceed()方法,// 直到currentInterceptorIndex的值等于this.interceptorsAndDynamicMethodMatchers.size() - 1,// 此时会执行invokeJoinpoint()方法。进而执行子类CglibAopProxy.CglibMethodInvocation.invokeJoinpoint()方法return invokeJoinpoint();}// 挨个的执行切面通知的方法Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);// 判断拦截器是否是InterceptorAndDynamicMethodMatcher(动态拦截器),// 动态拦截器要根据方法的参数的值来判断拦截器是否需要执行if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;// 检查方法的动态匹配,如果能够匹配,则执行对应的方法拦截器,如果切面有参数值,则对参数值进行赋值if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);} else {// 如果方法不能动态匹配,则递归执行proceed()return proceed();}}else {// 如果拦截器是一个普通的方法拦截器,则执行调用拦截器的invoke()方法return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}/*** 通过反射,调用执行目标对象的方法*/@Nullableprotected Object invokeJoinpoint() throws Throwable {return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);}// 省略其他}

在2.2.2中分析,Repository的方法调用时,会执行ReflectiveMethodInvocation.proceed()的方法,在该方法中,循环遍历所有的拦截器。

在拦截器的invoke(MethodInvocation invocation)方法中,传入的参数为this,即ReflectiveMethodInvocation本身。在拦截器中,如果需要执行下一个拦截器,需要再次调用invocation.proceed()方法。否则currentInterceptorIndex不会等于拦截器的个数减1,invokeJoinpoint()方法也将不会执行。

对于SimpleJpaRepository中实现的方法,会在执行完所有的拦截器之后,再次执行ReflectiveMethodInvocation.proceed()方法时,执行invokeJoinpoint()。在该方法中,执行target的方法,此处的target为SimpleJpaRepository对象。

SimpleJpaRepository

package org.springframework.data.jpa.repository.support;@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null";private final JpaEntityInformation<T, ?> entityInformation;private final EntityManager entityManager;private final PersistenceProvider provider;private @Nullable CrudMethodMetadata metadata;private @Nullable ProjectionFactory projectionFactory;private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;/*** 在RepositoryFactorySupport类的getTargetRepositoryViaReflection() -> instantiateClass()方法调用实例化* @param entityInformation Repository<T, ID>中的T的信息* @param entityManager 系统的EntityManager对象*/public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {Assert.notNull(entityInformation, "JpaEntityInformation must not be null");Assert.notNull(entityManager, "EntityManager must not be null");this.entityInformation = entityInformation;this.entityManager = entityManager;this.provider = PersistenceProvider.fromEntityManager(entityManager);}public SimpleJpaRepository(Class<T> domainClass, EntityManager entityManager) {this(JpaEntityInformationSupport.getEntityInformation(domainClass, entityManager), entityManager);}@Overridepublic void setRepositoryMethodMetadata(CrudMethodMetadata metadata) {this.metadata = metadata;}@Overridepublic void setEscapeCharacter(EscapeCharacter escapeCharacter) {this.escapeCharacter = escapeCharacter;}@Overridepublic void setProjectionFactory(ProjectionFactory projectionFactory) {this.projectionFactory = projectionFactory;}@Nullableprotected CrudMethodMetadata getRepositoryMethodMetadata() {return metadata;}protected Class<T> getDomainClass() {return entityInformation.getJavaType();}/*** 返回删除语句的sql。delete from %s x,其中%s为当前实体类的名称* @return*/private String getDeleteAllQueryString() {return getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName());}/*** 返回count语句的sql。select count(*) from %s x,其中%s为当前实体类的名称* @return*/private String getCountQueryString() {String countQuery = String.format(COUNT_QUERY_STRING, provider.getCountQueryPlaceholder(), "%s");return getQueryString(countQuery, entityInformation.getEntityName());}@Transactional@Overridepublic void deleteById(ID id) {Assert.notNull(id, ID_MUST_NOT_BE_NULL);// 删除之前,会先调用findById()查询记录,如果存在,再执行delete方法findById(id).ifPresent(this::delete);}@Override@Transactional@SuppressWarnings("unchecked")public void delete(T entity) {Assert.notNull(entity, "Entity must not be null");// 如果是新实体,则不能删除。有很多实现,比如判断对应的entity定义的Id属性是否有值等if (entityInformation.isNew(entity)) {return;}// 获取用户自定义的实体类Class<?> type = ProxyUtils.getUserClass(entity);// 通过id从EntityManager查询记录是否存在T existing = (T) entityManager.find(type, entityInformation.getId(entity));// if the entity to be deleted doesn't exist, delete is a NOOPif (existing == null) {return;}// 获取实体并删除entityManager.remove(entityManager.contains(entity) ? entity : entityManager.merge(entity));}@Override@Transactionalpublic void deleteAllById(Iterable<? extends ID> ids) {Assert.notNull(ids, "Ids must not be null");// 循环执行deleteByIdfor (ID id : ids) {deleteById(id);}}@Override@Transactionalpublic void deleteAllByIdInBatch(Iterable<ID> ids) {Assert.notNull(ids, "Ids must not be null");if (!ids.iterator().hasNext()) {return;}// 如果是复合idif (entityInformation.hasCompositeId()) {List<T> entities = new ArrayList<>();// generate entity (proxies) without accessing the database.// 生成实体(代理)而不访问数据库ids.forEach(id -> entities.add(getReferenceById(id)));// 复合id删除时,拼接删除语句,并执行deleteAllInBatch(entities);} else {// 执行delete from %s x where %s in :idsString queryString = String.format(DELETE_ALL_QUERY_BY_ID_STRING, entityInformation.getEntityName(),entityInformation.getIdAttribute().getName());Query query = entityManager.createQuery(queryString);// 一些JPA提供程序要求ids是Collection类型,因此如果尚未转换,则必须进行转换// 查询语句的ids赋值if (Collection.class.isInstance(ids)) {query.setParameter("ids", ids);} else {Collection<ID> idsCollection = StreamSupport.stream(ids.spliterator(), false).collect(Collectors.toCollection(ArrayList::new));query.setParameter("ids", idsCollection);}//  应用Query的hint。将添加的元数据中的hint信息添加到query中applyQueryHints(query);// 执行删除操作query.executeUpdate();}}@Override@Transactionalpublic void deleteAll(Iterable<? extends T> entities) {Assert.notNull(entities, "Entities must not be null");for (T entity : entities) {delete(entity);}}/*** 复合id删除时,拼接删除语句,并执行*/@Override@Transactionalpublic void deleteAllInBatch(Iterable<T> entities) {Assert.notNull(entities, "Entities must not be null");if (!entities.iterator().hasNext()) {return;}// 拼接删除语句,并执行applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), entities,entityManager).executeUpdate();}@Override@Transactionalpublic void deleteAll() {for (T element : findAll()) {delete(element);}}@Override@Transactionalpublic void deleteAllInBatch() {// 获取delete from %s x的查询对象Query query = entityManager.createQuery(getDeleteAllQueryString());// 设置hint信息applyQueryHints(query);// 执行queryquery.executeUpdate();}/*** 通过主键查询对象*/@Overridepublic Optional<T> findById(ID id) {Assert.notNull(id, ID_MUST_NOT_BE_NULL);// 获取Repository<T, ID>中定义的T的类型Class<T> domainType = getDomainClass();if (metadata == null) {return Optional.ofNullable(entityManager.find(domainType, id));}// 获取元数据中设置的锁类型。在Repository中通过@Lock(LockModeType.READ)添加的信息LockModeType type = metadata.getLockModeType();// 获取配置的hint信息Map<String, Object> hints = getHints();// 执行EntityManager.find()方法return Optional.ofNullable(type == null ? entityManager.find(domainType, id, hints) : entityManager.find(domainType, id, type, hints));}@Deprecated@Overridepublic T getOne(ID id) {return getReferenceById(id);}@Deprecated@Overridepublic T getById(ID id) {return getReferenceById(id);}/*** 通过entityManager.getReference()获取实体*/@Overridepublic T getReferenceById(ID id) {Assert.notNull(id, ID_MUST_NOT_BE_NULL);return entityManager.getReference(getDomainClass(), id);}@Overridepublic boolean existsById(ID id) {Assert.notNull(id, ID_MUST_NOT_BE_NULL);if (entityInformation.getIdAttribute() == null) {return findById(id).isPresent();}// 返回用于简单计数查询的占位符。默认实现返回x。子类PersistenceProvider返回*。select count(*) from tb_table tString placeholder = provider.getCountQueryPlaceholder();String entityName = entityInformation.getEntityName();// 获取主键属性名称Iterable<String> idAttributeNames = entityInformation.getIdAttributeNames();// 回用于执行给定id属性的查询字符串。返回select count(*) from %s x where x.id1Name = :id1Name and x.id2Name = :id2NameString existsQuery = QueryUtils.getExistsQueryString(entityName, placeholder, idAttributeNames);TypedQuery<Long> query = entityManager.createQuery(existsQuery, Long.class);// 设置hintapplyQueryHints(query);// 如果不是复合idif (!entityInformation.hasCompositeId()) {// 设置id的值query.setParameter(idAttributeNames.iterator().next(), id);// 如果有一条记录,说明存在对应id的记录,返回truereturn query.getSingleResult() == 1L;}// 如果是复合idfor (String idAttributeName : idAttributeNames) {// 获取对应id的值Object idAttributeValue = entityInformation.getCompositeIdAttributeValue(id, idAttributeName);boolean complexIdParameterValueDiscovered = idAttributeValue != null&& !query.getParameter(idAttributeName).getParameterType().isAssignableFrom(idAttributeValue.getClass());// 发现复杂Id参数值if (complexIdParameterValueDiscovered) {// fall-back to findById(id) which does the proper mapping for the parameter.// 返回到findById(id),它为参数执行正确的映射// 执行findById获取记录,记录存在,返回truereturn findById(id).isPresent();}// 设置查询语句的参数query.setParameter(idAttributeName, idAttributeValue);}// 如果有一条记录,说明存在对应id的记录,返回true,否则返回falsereturn query.getSingleResult() == 1L;}/*** 获取所有数据,通过Criteria接口进行查询*/@Overridepublic List<T> findAll() {return getQuery(null, Sort.unsorted()).getResultList();}@Overridepublic List<T> findAllById(Iterable<ID> ids) {Assert.notNull(ids, "Ids must not be null");if (!ids.iterator().hasNext()) {return Collections.emptyList();}// 如果是复合id,轮询使用findById()逐条获取记录if (entityInformation.hasCompositeId()) {List<T> results = new ArrayList<>();// 遍历执行findById(),获取对象,加入到List集合中for (ID id : ids) {findById(id).ifPresent(results::add);}return results;}// 如果不是复合id,则使用in查询语句获取多条记录Collection<ID> idCollection = Streamable.of(ids).toList();// 通过Criteria接口中的Path.in(),一次批量查询多条语句ByIdsSpecification<T> specification = new ByIdsSpecification<>(entityInformation);// 通过给定的Specification和排序规则,创建一个TypedQuery对象,并添加hint、锁等信息TypedQuery<T> query = getQuery(specification, Sort.unsorted());// query参数赋值,并执行return query.setParameter(specification.parameter, idCollection).getResultList();}@Overridepublic List<T> findAll(Sort sort) {return getQuery(null, sort).getResultList();}@Overridepublic Page<T> findAll(Pageable pageable) {if (pageable.isUnpaged()) {return new PageImpl<>(findAll());}return findAll((Specification<T>) null, pageable);}@Overridepublic Optional<T> findOne(Specification<T> spec) {try {// 最多获取两条记录,只获取其中的一条return Optional.of(getQuery(spec, Sort.unsorted()).setMaxResults(2).getSingleResult());} catch (NoResultException e) {return Optional.empty();}}@Overridepublic List<T> findAll(Specification<T> spec) {return getQuery(spec, Sort.unsorted()).getResultList();}@Overridepublic Page<T> findAll(Specification<T> spec, Pageable pageable) {TypedQuery<T> query = getQuery(spec, pageable);return pageable.isUnpaged() ? new PageImpl<>(query.getResultList()): readPage(query, getDomainClass(), pageable, spec);}@Overridepublic List<T> findAll(Specification<T> spec, Sort sort) {return getQuery(spec, sort).getResultList();}/*** 判断是否有符合Specification的记录* @param spec the {@link Specification} to use for the existence check, ust not be {@literal null}.* @return*/@Overridepublic boolean exists(Specification<T> spec) {// 创建返回Integer类型的queryCriteriaQuery<Integer> cq = this.entityManager.getCriteriaBuilder() //.createQuery(Integer.class) // 返回Integer类型.select(this.entityManager.getCriteriaBuilder().literal(1));// 从给定的Specification应用到给定的CriteriaQuery。如果有Specification,// 执行Specification.toPredicate(),并作为查询的whereapplySpecificationToCriteria(spec, getDomainClass(), cq);// 应用Repository中的方法元数据。将元数据中的@Lock、@QueryHint等信息添加到query中TypedQuery<Integer> query = applyRepositoryMethodMetadata(this.entityManager.createQuery(cq));// 执行查询,查询结果记录数量为1,则返回true,否则返回falsereturn query.setMaxResults(1).getResultList().size() == 1;}/*** 通过Specification作为条件,执行删除操作*/@Overridepublic long delete(Specification<T> spec) {CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();CriteriaDelete<T> delete = builder.createCriteriaDelete(getDomainClass());if (spec != null) {Predicate predicate = spec.toPredicate(delete.from(getDomainClass()), null, builder);if (predicate != null) {delete.where(predicate);}}return this.entityManager.createQuery(delete).executeUpdate();}@Overridepublic <S extends T, R> R findBy(Specification<T> spec, Function<FetchableFluentQuery<S>, R> queryFunction) {Assert.notNull(spec, "Specification must not be null");Assert.notNull(queryFunction, "Query function must not be null");return doFindBy(spec, getDomainClass(), queryFunction);}private <S extends T, R> R doFindBy(Specification<T> spec, Class<T> domainClass,Function<FetchableFluentQuery<S>, R> queryFunction) {Assert.notNull(spec, "Specification must not be null");Assert.notNull(queryFunction, "Query function must not be null");ScrollQueryFactory scrollFunction = (sort, scrollPosition) -> {Specification<T> specToUse = spec;if (scrollPosition instanceof KeysetScrollPosition keyset) {KeysetScrollSpecification<T> keysetSpec = new KeysetScrollSpecification<>(keyset, sort, entityInformation);sort = keysetSpec.sort();specToUse = specToUse.and(keysetSpec);}TypedQuery<T> query = getQuery(specToUse, domainClass, sort);if (scrollPosition instanceof OffsetScrollPosition offset) {if(!offset.isInitial()) {query.setFirstResult(Math.toIntExact(offset.getOffset()) + 1);}}return query;};Function<Sort, TypedQuery<T>> finder = sort -> getQuery(spec, domainClass, sort);SpecificationScrollDelegate<T> scrollDelegate = new SpecificationScrollDelegate<>(scrollFunction,entityInformation);FetchableFluentQueryBySpecification<?, T> fluentQuery = new FetchableFluentQueryBySpecification<>(spec, domainClass, finder,scrollDelegate, this::count, this::exists, this.entityManager, getProjectionFactory());return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);}@Overridepublic <S extends T> Optional<S> findOne(Example<S> example) {try {return Optional.of(getQuery(new ExampleSpecification<>(example, escapeCharacter), example.getProbeType(), Sort.unsorted()).setMaxResults(2).getSingleResult());} catch (NoResultException e) {return Optional.empty();}}@Overridepublic <S extends T> long count(Example<S> example) {return executeCountQuery(getCountQuery(new ExampleSpecification<>(example, escapeCharacter), example.getProbeType()));}@Overridepublic <S extends T> boolean exists(Example<S> example) {Specification<S> spec = new ExampleSpecification<>(example, this.escapeCharacter);CriteriaQuery<Integer> cq = this.entityManager.getCriteriaBuilder() //.createQuery(Integer.class) //.select(this.entityManager.getCriteriaBuilder().literal(1));applySpecificationToCriteria(spec, example.getProbeType(), cq);TypedQuery<Integer> query = applyRepositoryMethodMetadata(this.entityManager.createQuery(cq));return query.setMaxResults(1).getResultList().size() == 1;}@Overridepublic <S extends T> List<S> findAll(Example<S> example) {return getQuery(new ExampleSpecification<>(example, escapeCharacter), example.getProbeType(), Sort.unsorted()).getResultList();}@Overridepublic <S extends T> List<S> findAll(Example<S> example, Sort sort) {return getQuery(new ExampleSpecification<>(example, escapeCharacter), example.getProbeType(), sort).getResultList();}@Overridepublic <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {ExampleSpecification<S> spec = new ExampleSpecification<>(example, escapeCharacter);Class<S> probeType = example.getProbeType();TypedQuery<S> query = getQuery(new ExampleSpecification<>(example, escapeCharacter), probeType, pageable);return pageable.isUnpaged() ? new PageImpl<>(query.getResultList()) : readPage(query, probeType, pageable, spec);}@Overridepublic <S extends T, R> R findBy(Example<S> example, Function<FetchableFluentQuery<S>, R> queryFunction) {Assert.notNull(example, "Sample must not be null");Assert.notNull(queryFunction, "Query function must not be null");ExampleSpecification<S> spec = new ExampleSpecification<>(example, escapeCharacter);Class<S> probeType = example.getProbeType();return doFindBy((Specification<T>) spec, (Class<T>) probeType, queryFunction);}@Overridepublic long count() {TypedQuery<Long> query = entityManager.createQuery(getCountQueryString(), Long.class);applyQueryHintsForCount(query);return query.getSingleResult();}@Overridepublic long count(@Nullable Specification<T> spec) {return executeCountQuery(getCountQuery(spec, getDomainClass()));}@Transactional@Overridepublic <S extends T> S save(S entity) {Assert.notNull(entity, "Entity must not be null");if (entityInformation.isNew(entity)) {entityManager.persist(entity);return entity;} else {return entityManager.merge(entity);}}@Transactional@Overridepublic <S extends T> S saveAndFlush(S entity) {S result = save(entity);flush();return result;}@Transactional@Overridepublic <S extends T> List<S> saveAll(Iterable<S> entities) {Assert.notNull(entities, "Entities must not be null");List<S> result = new ArrayList<>();for (S entity : entities) {result.add(save(entity));}return result;}@Transactional@Overridepublic <S extends T> List<S> saveAllAndFlush(Iterable<S> entities) {List<S> result = saveAll(entities);flush();return result;}@Transactional@Overridepublic void flush() {entityManager.flush();}@Deprecatedprotected Page<T> readPage(TypedQuery<T> query, Pageable pageable, @Nullable Specification<T> spec) {return readPage(query, getDomainClass(), pageable, spec);}protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable,@Nullable Specification<S> spec) {if (pageable.isPaged()) {query.setFirstResult(PageableUtils.getOffsetAsInteger(pageable));query.setMaxResults(pageable.getPageSize());}return PageableExecutionUtils.getPage(query.getResultList(), pageable,() -> executeCountQuery(getCountQuery(spec, domainClass)));}protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Pageable pageable) {Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();return getQuery(spec, getDomainClass(), sort);}protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass,Pageable pageable) {Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();return getQuery(spec, domainClass, sort);}/*** 通过给定的Specification和排序规则,创建一个TypedQuery对象*/protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Sort sort) {return getQuery(spec, getDomainClass(), sort);}/*** 通过给定的Specification和排序规则,创建一个TypedQuery对象*/protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) {// 获取一个CriteriaBuilderCriteriaBuilder builder = entityManager.getCriteriaBuilder();// 创建CriteriaQueryCriteriaQuery<S> query = builder.createQuery(domainClass);// 获取一个Root,定义Criteria查询的根对象Root<S> root = applySpecificationToCriteria(spec, domainClass, query);// 查询rootquery.select(root);// 添加排序if (sort.isSorted()) {query.orderBy(toOrders(sort, root, builder));}// 创建Query,并添加hint、锁等信息return applyRepositoryMethodMetadata(entityManager.createQuery(query));}@Deprecatedprotected TypedQuery<Long> getCountQuery(@Nullable Specification<T> spec) {return getCountQuery(spec, getDomainClass());}protected <S extends T> TypedQuery<Long> getCountQuery(@Nullable Specification<S> spec, Class<S> domainClass) {CriteriaBuilder builder = entityManager.getCriteriaBuilder();CriteriaQuery<Long> query = builder.createQuery(Long.class);Root<S> root = applySpecificationToCriteria(spec, domainClass, query);if (query.isDistinct()) {query.select(builder.countDistinct(root));} else {query.select(builder.count(root));}// Remove all Orders the Specifications might have appliedquery.orderBy(Collections.emptyList());return applyRepositoryMethodMetadataForCount(entityManager.createQuery(query));}protected QueryHints getQueryHints() {return metadata == null ? NoHints.INSTANCE : DefaultQueryHints.of(entityInformation, metadata);}protected QueryHints getQueryHintsForCount() {return metadata == null ? NoHints.INSTANCE : DefaultQueryHints.of(entityInformation, metadata).forCounts();}/*** 从给定的Specification应用到给定的CriteriaQuery。如果有Specification,* 执行Specification.toPredicate(),并作为查询的where*/private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass,CriteriaQuery<S> query) {Assert.notNull(domainClass, "Domain class must not be null");Assert.notNull(query, "CriteriaQuery must not be null");// 获取一个Root。定义Criteria查询的根对象,Criteria查询的根定义为实体类型,它与SQL查询中的FROM子句类似Root<U> root = query.from(domainClass);// 如果没有Specification,直接返回rootif (spec == null) {return root;}// 创建CriteriaBuilder,用于构造条件查询、复合选择、表达式、谓词和排序CriteriaBuilder builder = entityManager.getCriteriaBuilder();// 执行Specification的toPredicate()方法,如果有返回值,则作为where语句,加入到query中Predicate predicate = spec.toPredicate(root, query, builder);if (predicate != null) {query.where(predicate);}// 返回rootreturn root;}/*** 应用Repository中的方法元数据。将元数据中的@Lock、@QueryHint等信息添加到query中*/private <S> TypedQuery<S> applyRepositoryMethodMetadata(TypedQuery<S> query) {if (metadata == null) {return query;}// 获取元数据中的锁信息LockModeType type = metadata.getLockModeType();TypedQuery<S> toReturn = type == null ? query : query.setLockMode(type);// 设置hintapplyQueryHints(toReturn);// 返回queryreturn toReturn;}/*** 应用Query的hint。将添加的元数据中的hint信息添加到query中。* Spring Data JPA 中的 Query Hint 是一种强大的工具,可帮助优化数据库查询并提高应用性能。* 与直接控制执行不同,Query Hint 会影响优化器(Optimizer)的决策过程。* 详见:https://springdoc.cn/spring-data-jpa-query-hints/*/private void applyQueryHints(Query query) {if (metadata == null) {return;}// 获取一个DefaultQueryHints对象,执行query的setHintgetQueryHints().withFetchGraphs(entityManager).forEach(query::setHint);// 从metadata元数据中获取设置的hint,并调用query::setHint,设置对应的hint名称及hint值applyComment(metadata, query::setHint);}private <S> TypedQuery<S> applyRepositoryMethodMetadataForCount(TypedQuery<S> query) {if (metadata == null) {return query;}applyQueryHintsForCount(query);return query;}private void applyQueryHintsForCount(Query query) {if (metadata == null) {return;}getQueryHintsForCount().forEach(query::setHint);applyComment(metadata, query::setHint);}/*** 获取hint信息*/private Map<String, Object> getHints() {Map<String, Object> hints = new HashMap<>();// 获取系统设置的hintgetQueryHints().withFetchGraphs(entityManager).forEach(hints::put);// 获取类元数据中定义的hintif (metadata != null) {applyComment(metadata, hints::put);}return hints;}/*** 从metadata元数据中获取设置的hint,并调用BiConsumer,设置对应的hint名称及hint值*/private void applyComment(CrudMethodMetadata metadata, BiConsumer<String, Object> consumer) {if (metadata.getComment() != null && provider.getCommentHintKey() != null) {consumer.accept(provider.getCommentHintKey(), provider.getCommentHintValue(this.metadata.getComment()));}}private ProjectionFactory getProjectionFactory() {if (projectionFactory == null) {projectionFactory = new SpelAwareProxyProjectionFactory();}return projectionFactory;}private static long executeCountQuery(TypedQuery<Long> query) {Assert.notNull(query, "TypedQuery must not be null");List<Long> totals = query.getResultList();long total = 0L;for (Long element : totals) {total += element == null ? 0 : element;}return total;}@SuppressWarnings("rawtypes")/*** 通过Criteria接口中的Path.in(),一次批量查询多条语句*/private static final class ByIdsSpecification<T> implements Specification<T> {private static final long serialVersionUID = 1L;private final JpaEntityInformation<T, ?> entityInformation;@Nullable ParameterExpression<Collection<?>> parameter;ByIdsSpecification(JpaEntityInformation<T, ?> entityInformation) {this.entityInformation = entityInformation;}@Overridepublic Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {// 获取主键的PathPath<?> path = root.get(entityInformation.getIdAttribute());parameter = (ParameterExpression<Collection<?>>) (ParameterExpression) cb.parameter(Collection.class);// 使用in语句批量查询return path.in(parameter);}}private static class ExampleSpecification<T> implements Specification<T> {private static final long serialVersionUID = 1L;private final Example<T> example;private final EscapeCharacter escapeCharacter;ExampleSpecification(Example<T> example, EscapeCharacter escapeCharacter) {Assert.notNull(example, "Example must not be null");Assert.notNull(escapeCharacter, "EscapeCharacter must not be null");this.example = example;this.escapeCharacter = escapeCharacter;}@Overridepublic Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {return QueryByExamplePredicateBuilder.getPredicate(root, cb, example, escapeCharacter);}}
}

SimpleJpaRepository实现了JpaRepositoryImplementation接口,它是CrudRepository的默认实现。

在自定义的Repository中,如果不实现JpaRepositoryImplementation接口,只是不能直接访问JpaRepositoryImplementation中提供的方法,而实际上是可以使用JpaRepositoryImplementation中的方法。如通过反射机制调用等。

SimpleJpaRepository中提供的CRUD的方法,要么是通过拼接SQL语句,要么是通过Criteria的查询,执行EntityManager对应方法实现。大部分核心代码都做了注释,对Criteria查询不清楚的,可以看

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

小结

限于篇幅,本篇就分享到这里,这里做一个小结:

1)通过上一篇源码,确认了Repository是代理对象,其中的target为SimpleJpaRepository对象;

2)介绍了访问JpaRepositoryImplementation中的方法时,如何通过动态代理执行到SimpleJpaRepository;

3)分析SimpleJpaRepository源码,核心是通过拼接SQL语句、Criteria的查询,执行EntityManager对应方法实现对数据库表的操作;

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

相关文章:

  • K-独立钻石(dfs),G-邪恶铭刻(贪心)
  • 反编译 Trino Dockerfile
  • 基于单片机的自行车里程监测系统的设计
  • 撤销最近一次的提交,使用git revert 和 git reset的区别
  • 【HarmonyOS尝鲜课】- 前言
  • TransFormer学习之VIT算法解析
  • 【调试笔记-20240525-Windows-配置 QEMU/x86_64 运行 OpenWrt-23.05 发行版并搭建 WordPress 博客网站】
  • 汽车制造业安全有效的设计图纸文件外发系统是什么样的?
  • Scala的简单学习一
  • 【JavaEE 初阶(十)】JVM
  • 【秒杀系统】从零开始打造简易秒杀系统(一):防止超卖
  • mysql实战——xtrabackup全量备份/增量备份及恢复
  • 机械产品3d模型网站让您的展示内容更加易于分享和传播
  • 大模型基础知识
  • 记录一次安装k8s初始化失败
  • 「面试题」如何实现一个圣杯布局?
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • github从入门到放弃(1)
  • LeetCode18.四数之和 JavaScript
  • Mocha测试初探
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • 读懂package.json -- 依赖管理
  • 分享一份非常强势的Android面试题
  • 前端攻城师
  • 学习笔记:对象,原型和继承(1)
  • 优秀架构师必须掌握的架构思维
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 智能合约Solidity教程-事件和日志(一)
  • scrapy中间件源码分析及常用中间件大全
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • ‌前端列表展示1000条大量数据时,后端通常需要进行一定的处理。‌
  • # 利刃出鞘_Tomcat 核心原理解析(八)-- Tomcat 集群
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #pragma once与条件编译
  • #QT 笔记一
  • (BFS)hdoj2377-Bus Pass
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (pojstep1.3.1)1017(构造法模拟)
  • (WSI分类)WSI分类文献小综述 2024
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (四) 虚拟摄像头vivi体验
  • (微服务实战)预付卡平台支付交易系统卡充值业务流程设计
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转载)虚函数剖析
  • .FileZilla的使用和主动模式被动模式介绍
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .net 调用php,php 调用.net com组件 --
  • .net 连接达梦数据库开发环境部署
  • @AliasFor注解
  • [ 常用工具篇 ] POC-bomber 漏洞检测工具安装及使用详解
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具