spring boot · 2024-07-30 0

springboot jpa 原理

一、代码

1. maven 依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.26</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

2. java 代码

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/temp
    username: root
    password: 123456
  jpa:
    hibernate:
      ddl-auto: update
@ToString
@Entity(name = "student")
public class StudentDO {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;
}
@Repository
public interface StudentDao extends JpaRepository<StudentDO, Long> {

    StudentDO findByIdAndName(Long id, String name);

    @Query("select s from student s WHERE s.id = ?1")
    StudentDO findNativeSql1(Long id);

    @Query(value = "select * from student WHERE id = ?1", nativeQuery = true)
    StudentDO findNativeSql2(Long id);
}
@Component
public class MyApplicationRunner implements ApplicationRunner {

    @Autowired
    private StudentDao studentDao;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<StudentDO> result1 = studentDao.findAll();
        StudentDO result2 = studentDao.findByIdAndName(1L, "zhangsan");
        StudentDO result3 = studentDao.findNativeSql1(1L);
        StudentDO result4 = studentDao.findNativeSql2(1L);

        System.out.println(result1);
        System.out.println(result2);
        System.out.println(result3);
        System.out.println(result4);
    }
}
@SpringBootApplication
public class Boot {

    public static void main(String[] args) {
        SpringApplication.run(Boot.class, args);
    }
}

3. 日志

Hibernate: select studentdo0_.id as id1_0_, studentdo0_.name as name2_0_ from student studentdo0_
Hibernate: select studentdo0_.id as id1_0_, studentdo0_.name as name2_0_ from student studentdo0_ where studentdo0_.id=? and studentdo0_.name=?
Hibernate: select studentdo0_.id as id1_0_, studentdo0_.name as name2_0_ from student studentdo0_ where studentdo0_.id=?
Hibernate: select * from student WHERE id = ?
[StudentDO(id=1, name=zhangsan)]
StudentDO(id=1, name=zhangsan)
StudentDO(id=1, name=zhangsan)
StudentDO(id=1, name=zhangsan)

二、原理

1.加载 JpaRepositoriesAutoConfiguration

org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件下有:

org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration

2.加载 JpaRepositoriesRegistrar

JpaRepositoriesAutoConfiguration 加载 JpaRepositoriesImportSelector,JpaRepositoriesImportSelector 加载 JpaRepositoriesRegistrar

JpaRepositoriesRegistrar 又继承了抽象类 AbstractRepositoryConfigurationSourceSupport 类。这是一个 ImportBeanDefinitionRegistrar,设计目的就是在 SpringBoot 自动发现机制中发现用户自定义的 JpaRepository。在 Spring 容器启动中,该 ImportBeanDefinitionRegistrar 就会执行。

// JpaRepositoriesAutoConfiguration.java
@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class })
@ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "enabled", havingValue = "true",
        matchIfMissing = true)
@Import(JpaRepositoriesImportSelector.class)
public class JpaRepositoriesAutoConfiguration {

    ...
    static class JpaRepositoriesImportSelector implements ImportSelector {

        private static final boolean ENVERS_AVAILABLE = ClassUtils.isPresent(
                "org.springframework.data.envers.repository.config.EnableEnversRepositories",
                JpaRepositoriesImportSelector.class.getClassLoader());

        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[] { determineImport() };
        }

        private String determineImport() {
            return ENVERS_AVAILABLE ? EnversRevisionRepositoriesRegistrar.class.getName()
                    : JpaRepositoriesRegistrar.class.getName();
        }

    }
}

JpaRepositoriesRegistrar 执行 registerBeanDefinitions 方法注册 bean

// JpaRepositoriesRegistrar.java
class JpaRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
            BeanNameGenerator importBeanNameGenerator) {
        RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(
                getConfigurationSource(registry, importBeanNameGenerator), this.resourceLoader, this.environment);
        delegate.registerRepositoriesIn(registry, getRepositoryConfigurationExtension());
    }

    private AnnotationRepositoryConfigurationSource getConfigurationSource(BeanDefinitionRegistry registry,
            BeanNameGenerator importBeanNameGenerator) {
        AnnotationMetadata metadata = AnnotationMetadata.introspect(getConfiguration());
        return new AutoConfiguredAnnotationRepositoryConfigurationSource(metadata, getAnnotation(), this.resourceLoader,
                this.environment, registry, importBeanNameGenerator) {
        };
    }

    @Override
    protected Class<? extends Annotation> getAnnotation() {
        return EnableJpaRepositories.class;
    }

    @Override
    protected Class<?> getConfiguration() {
        return EnableJpaRepositoriesConfiguration.class;
    }

    @Override
    protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
        return new JpaRepositoryConfigExtension();
    }

    ...
    @EnableJpaRepositories
    private static class EnableJpaRepositoriesConfiguration {

    }
}
// EnableJpaRepositories.java
public @interface EnableJpaRepositories {
    ... 
    String entityManagerFactoryRef() default "entityManagerFactory";

    String transactionManagerRef() default "transactionManager";

    Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;

    String repositoryImplementationPostfix() default "Impl";

    Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;

    Class<?> repositoryFactoryBeanClass() default JpaRepositoryFactoryBean.class;
    ...
}

3.加载自定义 JpaRepository 的 BeanDefinition

对于自定义的 JpaRepository,例如 studentDao,BeanDefinition 注册到 spring 容器,beanClass 是 org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean

RepositoryConfigurationExtension.registerBeansForRoot 会注册 EntityManagerBeanDefinitionRegistrarPostProcessor、JpaMetamodelMappingContextFactoryBean、PersistenceAnnotationBeanPostProcessor、DefaultJpaContext、JpaMetamodelCacheCleanup、JpaEvaluationContextExtension

RepositoryComponentProvider 负责找出 找出实现 Repository 接口,或有 RepositoryDefinition 注解的类

// RepositoryConfigurationDelegate.java
public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry,
        RepositoryConfigurationExtension extension) {
    ...
    extension.registerBeansForRoot(registry, configurationSource);

    RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension,
            configurationSource, resourceLoader, environment);
    List<BeanComponentDefinition> definitions = new ArrayList<>();
    ...
    Collection<RepositoryConfiguration<RepositoryConfigurationSource>> configurations = extension
            .getRepositoryConfigurations(configurationSource, resourceLoader, inMultiStoreMode);

    Map<String, RepositoryConfiguration<?>> configurationsByRepositoryName = new HashMap<>(configurations.size());

    for (RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration : configurations) {

        configurationsByRepositoryName.put(configuration.getRepositoryInterface(), configuration);

        BeanDefinitionBuilder definitionBuilder = builder.build(configuration);

        extension.postProcess(definitionBuilder, configurationSource);

        if (isXml) {
            extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource) configurationSource);
        } else {
            extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
        }

        AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
        beanDefinition.setResourceDescription(configuration.getResourceDescription());

        String beanName = configurationSource.generateBeanName(beanDefinition);

        if (logger.isTraceEnabled()) {
            logger.trace(LogMessage.format(REPOSITORY_REGISTRATION, extension.getModuleName(), beanName, configuration.getRepositoryInterface(),
                    configuration.getRepositoryFactoryBeanClassName()));
        }

        beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, configuration.getRepositoryInterface());

        registry.registerBeanDefinition(beanName, beanDefinition);
        definitions.add(new BeanComponentDefinition(beanDefinition, beanName));
    }

    potentiallyLazifyRepositories(configurationsByRepositoryName, registry, configurationSource.getBootstrapMode());
    ...
    return definitions;
}
// JpaRepositoryConfigExtension.java
@Override
public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource config) {

    super.registerBeansForRoot(registry, config);

    Object source = config.getSource();

    registerLazyIfNotAlreadyRegistered(
            () -> new RootBeanDefinition(EntityManagerBeanDefinitionRegistrarPostProcessor.class), registry,
            EM_BEAN_DEFINITION_REGISTRAR_POST_PROCESSOR_BEAN_NAME, source);

    registerLazyIfNotAlreadyRegistered(() -> new RootBeanDefinition(JpaMetamodelMappingContextFactoryBean.class),
            registry, JPA_MAPPING_CONTEXT_BEAN_NAME, source);

    registerLazyIfNotAlreadyRegistered(() -> new RootBeanDefinition(PAB_POST_PROCESSOR), registry,
            AnnotationConfigUtils.PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME, source);

    // Register bean definition for DefaultJpaContext

    registerLazyIfNotAlreadyRegistered(() -> {

        RootBeanDefinition contextDefinition = new RootBeanDefinition(DefaultJpaContext.class);
        contextDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);

        return contextDefinition;

    }, registry, JPA_CONTEXT_BEAN_NAME, source);

    registerIfNotAlreadyRegistered(() -> new RootBeanDefinition(JPA_METAMODEL_CACHE_CLEANUP_CLASSNAME), registry,
            JPA_METAMODEL_CACHE_CLEANUP_CLASSNAME, source);

    // EvaluationContextExtension for JPA specific SpEL functions

    registerIfNotAlreadyRegistered(() -> {

        Object value = AnnotationRepositoryConfigurationSource.class.isInstance(config) //
                ? config.getRequiredAttribute(ESCAPE_CHARACTER_PROPERTY, Character.class) //
                : config.getAttribute(ESCAPE_CHARACTER_PROPERTY).orElse("\\");

        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(JpaEvaluationContextExtension.class);
        builder.addConstructorArgValue(value);

        return builder.getBeanDefinition();

    }, registry, JpaEvaluationContextExtension.class.getName(), source);
}

getBasePackages() 得到扫描为启动类目录,例如 org.example
RepositoryComponentProvider 负责找出 找出实现 Repository 接口,或有 RepositoryDefinition 注解的类

// AbstractRepositoryConfigurationSourceSupport$1.java
@Override
public Streamable<BeanDefinition> getCandidates(ResourceLoader loader) {

    RepositoryComponentProvider scanner = new RepositoryComponentProvider(getIncludeFilters(), registry);
    scanner.setConsiderNestedRepositoryInterfaces(shouldConsiderNestedRepositories());
    scanner.setEnvironment(environment);
    scanner.setResourceLoader(loader);

    getExcludeFilters().forEach(it -> scanner.addExcludeFilter(it));

    return Streamable.of(() -> getBasePackages().stream()//
            .flatMap(it -> scanner.findCandidateComponents(it).stream()));
}

protected Streamable<String> getBasePackages() {
    return Streamable.of(AutoConfigurationPackages.get(this.beanFactory));
}

4.注册 JpaRepositoryFactoryBean 实例

前面已把自定义的 JpaRepository,例如 studentDao,生成 BeanDefinition,其 name 是 studentDao,beanClass 是 org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean,注册到 spring 容器

5.生成代理类 SimpleJpaRepository

repository 是 JpaRepositoryFactory

// JpaRepositoryFactoryBean.java
public JpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
    super(repositoryInterface);
}

@NonNull
public T getObject() {
    return this.repository.get();
}

public void afterPropertiesSet() {

    this.factory = createRepositoryFactory();
    ...
    this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));
    ...
    if (!lazyInit) {
        this.repository.get();
    }
}

创建代理对象,target 是 SimpleJpaRepository,repositoryInterface 是 StudentDao

postProcessors 有 5 个:

  1. CrudMethodMetadataPostProcessor
  2. JpaRepositoryFactory$lambda
  3. PersistenceExceptionTranslationRepositoryProxyPostProcessor
  4. TransactionalRepositoryProxyPostProcessor
  5. EventPublishingRepositoryProxyPostProcessor
  • CrudMethodMetadataPostProcessor 会 addAdvice 为 CrudMethodMetadataPopulatingMethodInterceptor
  • paRepositoryFactory$lambda 会 addAdvice 为 SurroundingTransactionDetectorMethodInterceptor.INSTANCE
  • PersistenceExceptionTranslationRepositoryProxyPostProcessor 会 addAdvice 为 PersistenceExceptionTranslationInterceptor
  • TransactionalRepositoryProxyPostProcessor 会 addAdvice 为 TransactionInterceptor
  • EventPublishingRepositoryProxyPostProcessor 会 addAdvice 为 EventPublishingMethodInterceptor
// JpaRepositoryFactory.java
public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments)
    ...
    ProxyFactory result = new ProxyFactory();
    result.setTarget(target);
    result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);

    if (MethodInvocationValidator.supports(repositoryInterface)) {
        result.addAdvice(new MethodInvocationValidator());
    }

    result.addAdvisor(ExposeInvocationInterceptor.ADVISOR);

    if (!postProcessors.isEmpty()) {
        postProcessors.forEach(processor -> {
            ...
            processor.postProcess(result, information);
            ...
        });
    }

    if (DefaultMethodInvokingMethodInterceptor.hasDefaultMethods(repositoryInterface)) {
        result.addAdvice(new DefaultMethodInvokingMethodInterceptor());
    }

    ... 
    result.addAdvice(new QueryExecutorMethodInterceptor(information, getProjectionFactory(), queryLookupStrategy,
        namedQueries, queryPostProcessors, methodInvocationListeners));

    result.addAdvice(
            new ImplementationMethodExecutionInterceptor(information, compositionToUse, methodInvocationListeners));

    T repository = (T) result.getProxy(classLoader);
    ...
    return repository;
}

6.执行方法

advisors 有:

  1. advisor 为 ExposeInvocationInterceptor$1,pointcut 为 Pointcut.TRUE,advice 为 ExposeInvocationInterceptor
  2. advisor 为 DefaultPointcutAdvisor,pointcut 为 Pointcut.TRUE,advice 为 CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor
  3. advisor 为 DefaultPointcutAdvisor,pointcut 为 Pointcut.TRUE,advice 为 PersistenceExceptionTranslationInterceptor
  4. advisor 为 DefaultPointcutAdvisor,pointcut 为 Pointcut.TRUE,advice 为 TransactionInterceptor
  5. advisor 为 DefaultPointcutAdvisor,pointcut 为 Pointcut.TRUE,advice 为 DefaultMethodInvokingMethodInterceptor
  6. advisor 为 DefaultPointcutAdvisor,pointcut 为 Pointcut.TRUE,advice 为 QueryExecutorMethodInterceptor
  7. advisor 为 DefaultPointcutAdvisor,pointcut 为 Pointcut.TRUE,advice 为 RepositoryFactorySupport$ImplementationMethodExecutionInterceptor
  8. advisor 为 DefaultPointcutAdvisor,pointcut 为 AnnotationMatchingPointcut,匹配被 @Repository 标注的类,advice 为 PersistenceExceptionTranslationInterceptor

TransactionInterceptor 用于开始事务和关闭事务

// JdkDynamicAopProxy.java
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    ...
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;
    ...
        target = targetSource.getTarget();
                    Class<?> targetClass = (target != null ? target.getClass() : null);
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    if (chain.isEmpty()) {
        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();
    }       
    ...
    return retVal;
}

6.1.执行 baseClass 方法

studentDao.findAll() 会执行 RepositoryFactorySupport$ImplementationMethodExecutionInterceptor,会调用 SimpleJpaRepository 的 findAll() 方法

// QueryExecutorMethodInterceptor.java
@Nullable
private Object doInvoke(MethodInvocation invocation) throws Throwable {

    Method method = invocation.getMethod();

    if (hasQueryFor(method)) {

        RepositoryMethodInvoker invocationMetadata = invocationMetadataCache.get(method);

        if (invocationMetadata == null) {
            invocationMetadata = RepositoryMethodInvoker.forRepositoryQuery(method, queries.get(method));
            invocationMetadataCache.put(method, invocationMetadata);
        }

        return invocationMetadata.invoke(repositoryInformation.getRepositoryInterface(), invocationMulticaster,
                invocation.getArguments());
    }

    return invocation.proceed();
}
// RepositoryFactorySupport$ImplementationMethodExecutionInterceptor    
@Nullable
@Override
public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable {
    Method method = invocation.getMethod();
    Object[] arguments = invocation.getArguments();
    ...
    return composition.invoke(invocationMulticaster, method, arguments);
}
// RepositoryComposition.java
Object invoke(RepositoryInvocationMulticaster listener, Method method, Object[] args) throws Throwable {
    ...
    return fragments.invoke(metadata != null ? metadata.getRepositoryInterface() : method.getDeclaringClass(), listener,
            method, methodToCall, argumentConverter.apply(methodToCall, args));
}
// RepositoryComposition$RepositoryFragments.java
@Nullable
Object invoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster listener, Method invokedMethod,
        Method methodToCall, Object[] args) throws Throwable {
    ...
    return repositoryMethodInvoker.invoke(repositoryInterface, listener, args);
}

invokable 为 RepositoryMethodInvoker$RepositoryFragmentMethodInvoker$$Lambda$795/773765215

// RepositoryMethodInvoker$RepositoryQueryMethodInvoker.java
@Nullable
public Object invoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args)
        throws Exception {
    return shouldAdaptReactiveToSuspended() ? doInvokeReactiveToSuspended(repositoryInterface, multicaster, args)
            : doInvoke(repositoryInterface, multicaster, args);
}

@Nullable
private Object doInvoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args)
        throws Exception {
    ...
    Object result = invokable.invoke(args);
    ...
    return result;
}

baseClassMethod.invoke(instance, args) 调用 SimpleJpaRepository 的方法

// RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.java
public RepositoryFragmentMethodInvoker(CoroutineAdapterInformation adapterInformation, Method declaredMethod,
        Object instance, Method baseClassMethod) {
    super(declaredMethod, args -> {

        if (adapterInformation.isAdapterMethod()) {
            Object[] invocationArguments = new Object[args.length - 1];
            System.arraycopy(args, 0, invocationArguments, 0, invocationArguments.length);

            return baseClassMethod.invoke(instance, invocationArguments);
        }

        return baseClassMethod.invoke(instance, args);
    });
    this.adapterInformation = adapterInformation;
}

protected RepositoryMethodInvoker(Method method, Invokable invokable) {

    this.method = method;
    this.invokable = invokable;
    ...
}

@Nullable
public Object invoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args)
        throws Exception {
    return shouldAdaptReactiveToSuspended() ? doInvokeReactiveToSuspended(repositoryInterface, multicaster, args)
            : doInvoke(repositoryInterface, multicaster, args);
}

@Nullable
private Object doInvoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args)
        throws Exception {
    ...
    try {

        Object result = invokable.invoke(args);
        ...
        return result;
    } catch (Exception e) {
        ...
    }
}
// SimpleJpaRepository.java
@Override
public List<T> findAll() {
    return getQuery(null, Sort.unsorted()).getResultList();
}

6.2.执行自定义方法

执行 studentDao.findByIdAndName(1L, "zhangsan"),

RepositoryQuery 为 PartTreeJpaQuery

// QueryExecutorMethodInterceptor.java
@Nullable
private Object doInvoke(MethodInvocation invocation) throws Throwable {

    Method method = invocation.getMethod();

    if (hasQueryFor(method)) {

        RepositoryMethodInvoker invocationMetadata = invocationMetadataCache.get(method);

        if (invocationMetadata == null) {
            invocationMetadata = RepositoryMethodInvoker.forRepositoryQuery(method, queries.get(method));
            invocationMetadataCache.put(method, invocationMetadata);
        }

        return invocationMetadata.invoke(repositoryInformation.getRepositoryInterface(), invocationMulticaster,
                invocation.getArguments());
    }

    return invocation.proceed();
}
// RepositoryMethodInvoker.java
static RepositoryQueryMethodInvoker forRepositoryQuery(Method declaredMethod, RepositoryQuery query) {
    return new RepositoryQueryMethodInvoker(declaredMethod, query);
}

private static class RepositoryQueryMethodInvoker extends RepositoryMethodInvoker {
    public RepositoryQueryMethodInvoker(Method method, RepositoryQuery repositoryQuery) {
        super(method, repositoryQuery::execute);
    }
}
// RepositoryMethodInvoker.java
protected RepositoryMethodInvoker(Method method, Invokable invokable) {
    this.method = method;
    this.invokable = invokable;
    ...
}

invokable 是 RepositoryMethodInvoker$RepositoryQueryMethodInvoker$$Lambda$810/2053481312

// RepositoryMethodInvoker$RepositoryQueryMethodInvoker.java
@Nullable
public Object invoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args)
        throws Exception {
    return shouldAdaptReactiveToSuspended() ? doInvokeReactiveToSuspended(repositoryInterface, multicaster, args)
            : doInvoke(repositoryInterface, multicaster, args);
}

@Nullable
private Object doInvoke(Class<?> repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args)
        throws Exception {
    ...
    Object result = invokable.invoke(args);
    ...
    return result;
}
// PartTreeJpaQuery,java
@Nullable
@Override
public Object execute(Object[] parameters) {
    return doExecute(getExecution(), parameters);
}

@Nullable
private Object doExecute(JpaQueryExecution execution, Object[] values) {

    JpaParametersParameterAccessor accessor = obtainParameterAccessor(values);
    Object result = execution.execute(this, accessor);

    ResultProcessor withDynamicProjection = method.getResultProcessor().withDynamicProjection(accessor);
    return withDynamicProjection.processResult(result, new TupleConverter(withDynamicProjection.getReturnedType()));
}
// JpaQueryExecution$SingleEntityExecution.java
@Nullable
public Object execute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
    Object result;

    try {
        result = doExecute(query, accessor);
    } catch (NoResultException e) {
        return null;
    }
    ...
}

@Override
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {

    return query.createQuery(accessor).getSingleResult();
}