Spring Data JPA 实现原理

Spring Data JPA 实现原理

在使用Spring Data JPA的时候,只需使用简单的接口定义,通过JPA约定好的命名格式书写对于的方法,就能够完成日常开发中的大部分数据库交互的场景,看下官方给出的例子:

@Repository
public interface SimpleUserRepository extends CrudRepository<User, Long> {

    /**
     * Find the user with the given username. This method will be translated into a query using the
     * {@link javax.persistence.NamedQuery} annotation at the {@link User} class.
     *
     * @param lastname
     * @return
     */
    User findByTheUsersName(String username);

    /**
     * Uses {@link Optional} as return and parameter type.
     *
     * @param username
     * @return
     */
    Optional<User> findByUsername(Optional<String> username);
    
    // ...
}

可以知道,这里使用的是接口,而Java中的接口要使用必须要有实现类,那么JPA时怎么做到的呢,想到这里基本就可以猜出来Spring Data JPA是通过动态代理来实现,但是具体是怎么操作的呢?

@EnableJpaRepositories说起

配置Spring Data JPA的时候通常就是通过@EnableJpaRepositories开启的,而通过注解就可以让整个JPA run起来,其中最重要的就是在@EnableJpaRepositories中import了JpaRepositoriesRegistrar,而这个配置就是入口所在。

先说明一下,Spring Data可不仅仅只有JPA的实现,还有其他各种各样的实现(如,JDBC,Redis,LDAP等),所以基本都是基于SPI(Service Provider Interface)解耦分层,所以大部分实现操作都是在spring-data-commons包中完成的。

JpaRepositoriesRegistrar

首先来看JpaRepositoriesRegistrar提供的功能,在spring-data-jpa包中,主要是用于告诉spring-data-commons抽象层的一些具体配置与解析:

  • getAnnotation(),提供JAP配置注解类,即@EnableJpaRepositories
  • getExtension(),提供JpaRepositoryConfigExtension,用于解析@EnableJpaRepositories
RepositoryBeanDefinitionRegistrarSupport

JpaRepositoriesRegistrar继承于RepositoryBeanDefinitionRegistrarSupport,它就是加载Repositories的关键:

  • registerBeanDefinitions,向Spring容器注册JpaRepositoryFactoryBean

大致步骤

所以,大致可以分为三大块,JPA加载的入口,注册JpaRepositoryFactoryBean和通过JpaRepositoryFactoryBean创建Repository

  • @EnableJpaRepositories import JpaRepositoriesRegistrar
  • JpaRepositoriesRegistrar.registerBeanDefinitions,注册JpaRepositoryFactoryBean
  • JpaRepositoryFactoryBean.afterPropertiesSet,创建Repository
JpaRepositoryFactoryBean如何创建Repository

其实,最关键的还是Repository是如何被创建出来的,首先看afterPropertiesSet

public void afterPropertiesSet() {

    this.factory = createRepositoryFactory();
    this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey);
    this.factory.setNamedQueries(namedQueries);
    this.factory.setEvaluationContextProvider(
            evaluationContextProvider.orElseGet(() -> QueryMethodEvaluationContextProvider.DEFAULT));
    this.factory.setBeanClassLoader(classLoader);
    this.factory.setBeanFactory(beanFactory);

    if (publisher != null) {
        this.factory.addRepositoryProxyPostProcessor(new EventPublishingRepositoryProxyPostProcessor(publisher));
    }

    repositoryBaseClass.ifPresent(this.factory::setRepositoryBaseClass);

    RepositoryFragments customImplementationFragment = customImplementation //
            .map(RepositoryFragments::just) //
            .orElseGet(RepositoryFragments::empty);

    RepositoryFragments repositoryFragmentsToUse = this.repositoryFragments //
            .orElseGet(RepositoryFragments::empty) //
            .append(customImplementationFragment);

    this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);

    // Make sure the aggregate root type is present in the MappingContext (e.g. for auditing)
    this.mappingContext.ifPresent(it -> it.getPersistentEntity(repositoryMetadata.getDomainType()));
    
    //这里创建Repository    
    this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));

    if (!lazyInit) {
        this.repository.get();
    }
}

具体来看RepositoryFactorySupport.getRepository()方法

public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {

    if (LOG.isDebugEnabled()) {
        LOG.debug("Initializing repository instance for {}…", repositoryInterface.getName());
    }

    Assert.notNull(repositoryInterface, "Repository interface must not be null!");
    Assert.notNull(fragments, "RepositoryFragments must not be null!");

    RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface);
    RepositoryComposition composition = getRepositoryComposition(metadata, fragments);
    //指定RepositoryBaseClass为SimpleJpaRepository
    RepositoryInformation information = getRepositoryInformation(metadata, composition);

    validate(information, composition);

    Object target = getTargetRepository(information);

    // Create proxy
    ProxyFactory result = new ProxyFactory();
    result.setTarget(target);
    result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);
    
    //Bean Validation Advice
    if (MethodInvocationValidator.supports(repositoryInterface)) {
        result.addAdvice(new MethodInvocationValidator());
    }
    //事务 Advice
    result.addAdvice(SurroundingTransactionDetectorMethodInterceptor.INSTANCE);
    result.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
    
    //RepositoryProxyPostProcessor处理
    postProcessors.forEach(processor -> processor.postProcess(result, information));
    
    //默认方法 Advice,背后实现为SimpleJpaRepository
    result.addAdvice(new DefaultMethodInvokingMethodInterceptor());

    ProjectionFactory projectionFactory = getProjectionFactory(classLoader, beanFactory);
    //自定义方法 Advice
    result.addAdvice(new QueryExecutorMethodInterceptor(information, projectionFactory));

    composition = composition.append(RepositoryFragment.implemented(target));
    //自定义实现方法的 Advice
    result.addAdvice(new ImplementationMethodExecutionInterceptor(composition));
    
    //通过动态代理创建Repository
    T repository = (T) result.getProxy(classLoader);

    if (LOG.isDebugEnabled()) {
        LOG.debug("Finished creation of repository instance for {}.", repositoryInterface.getName());
    }

    return repository;
}

通过源码我们可以知道,Spring Data JPA是基于SimpleJpaRepository类的动态代理实现,通过AOP实现对自定义方法进行处理的

推荐阅读更多精彩内容