SpringBoot2.0原始碼分析(四):spring-data-jpa分析

貳級天災發表於2018-11-18

SpringBoot具體整合rabbitMQ可參考:SpringBoot2.0應用(四):SpringBoot2.0之spring-data-jpa

JpaRepositories自動注入

當專案中存在org.springframework.data.jpa.repository.JpaRepository類,並且已經注入過資料來源javax.sql.DataSource,同時沒有注入過org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtensionorg.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());
	}

    ......
}
複製程式碼

可以看出,到AbstractRepositoryConfigurationSourceSupportRepository的Bean進行了定義。下面來具體看看Repositoryd的建立。

Repository的建立

我們先來看下RepositoryConfigurationDelegateregisterRepositoriesIn方法。

	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建立。建立的方法在DeclaredQueryLookupStrategyresolveQuery中。

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,接著是根據關鍵字建立,然後是通用方法。


本篇到此結束,如果讀完覺得有收穫的話,歡迎點贊、關注、加公眾號【貳級天災】,查閱更多精彩歷史!!!

SpringBoot2.0原始碼分析(四):spring-data-jpa分析

相關文章