美文网首页Java 杂谈
Spring Data JPA 实现原理

Spring Data JPA 实现原理

作者: SevenLin1993 | 来源:发表于2019-03-31 14:51 被阅读0次

    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实现对自定义方法进行处理的

    相关文章

      网友评论

        本文标题:Spring Data JPA 实现原理

        本文链接:https://www.haomeiwen.com/subject/yvtubqtx.html