SpringBoot2.0原始碼分析(四):spring-data-jpa分析
當專案中存在org.springframework.data.jpa.repository.JpaRepository
類,並且已經注入過資料來源javax.sql.DataSource
,同時沒有注入過org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension
和org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean
時,會通過@Import
註解匯入org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfigureRegistrar
,由它完成對JPA的支援。JpaRepositoriesAutoConfigureRegistrar
又繼承自AbstractRepositoryConfigurationSourceSupport
。來看下AbstractRepositoryConfigurationSourceSupport
的具體內容。
public abstract class AbstractRepositoryConfigurationSourceSupport implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { private ResourceLoader resourceLoader; private BeanFactory beanFactory; private Environment environment; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { new RepositoryConfigurationDelegate(getConfigurationSource(registry), this.resourceLoader, this.environment).registerRepositoriesIn(registry, getRepositoryConfigurationExtension()); } ...... } 複製程式碼
可以看出,到AbstractRepositoryConfigurationSourceSupport
對Repository
的Bean進行了定義。下面來具體看看Repositoryd的建立。
Repositoryd的建立
我們先來看下RepositoryConfigurationDelegate
的registerRepositoriesIn
方法。
public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension) { extension.registerBeansForRoot(registry, configurationSource); RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, resourceLoader, environment); List<BeanComponentDefinition> definitions = new ArrayList<>(); for (RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration : extension .getRepositoryConfigurations(configurationSource, resourceLoader, inMultiStoreMode)) { 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(); String beanName = configurationSource.generateBeanName(beanDefinition); ...... beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, configuration.getRepositoryInterface()); registry.registerBeanDefinition(beanName, beanDefinition); definitions.add(new BeanComponentDefinition(beanDefinition, beanName)); } return definitions; } 複製程式碼
到這裡其實只是建立了repository的實體Bean的BeanDefinition。前期準備做好了,實際建立repository是在RepositoryFactorySupport
的getRepository方法。
public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) { 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); 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); if (MethodInvocationValidator.supports(repositoryInterface)) { result.addAdvice(new MethodInvocationValidator()); } result.addAdvice(SurroundingTransactionDetectorMethodInterceptor.INSTANCE); result.addAdvisor(ExposeInvocationInterceptor.ADVISOR); postProcessors.forEach(processor -> processor.postProcess(result, information)); result.addAdvice(new DefaultMethodInvokingMethodInterceptor()); ProjectionFactory projectionFactory = getProjectionFactory(classLoader, beanFactory); result.addAdvice(new QueryExecutorMethodInterceptor(information, projectionFactory)); composition = composition.append(RepositoryFragment.implemented(target)); result.addAdvice(new ImplementationMethodExecutionInterceptor(composition)); return (T) result.getProxy(classLoader); } 複製程式碼
首先去獲取我們寫的repository介面的元資料,包括實體的ID型別,管理的實體型別等。接著獲取repository的組合,主要包含repository的方法資訊。然後再根據它倆的組合得到一個target。這個target其實就是一個SimpleJpaRepository實體,裡面包含了一些通用的方法。只有這些還不夠,於是有了後面的代理工廠,對這個target進行進一步處理。包括事務支援,異常處理和SQL創造等。我們主要看一下SQL建立。建立的方法在DeclaredQueryLookupStrategy
的resolveQuery
中。
protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) { RepositoryQuery query = JpaQueryFactory.INSTANCE.fromQueryAnnotation(method, em, evaluationContextProvider); if (null != query) { return query; } query = JpaQueryFactory.INSTANCE.fromProcedureAnnotation(method, em); if (null != query) { return query; } String name = method.getNamedQueryName(); if (namedQueries.hasQuery(name)) { return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, namedQueries.getQuery(name), evaluationContextProvider); } query = NamedQuery.lookupFrom(method, em); if (null != query) { return query; } throw new IllegalStateException( String.format("Did neither find a NamedQuery nor an annotated query for method %s!", method)); } 複製程式碼
該方法的邏輯是先找有註解的,這個包括@Query
和@Procedure
,接著是根據關鍵字建立,然後是通用方法。