SpringBoot2.0源码分析(四):spring-data-jpa分析

栏目: Java · 发布时间: 6年前

内容简介:当项目中存在可以看出,到我们先来看下

当项目中存在 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的创建。

Repositoryd的创建

我们先来看下 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 ,接着是根据关键字创建,然后是通用方法。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机程序设计艺术(第1卷)

计算机程序设计艺术(第1卷)

[美] Donald E. Knuth / 清华大学出版社 / 2002-9 / 80.00元

第1卷首先介绍编程的基本概念和技术,然后详细讲解信息结构方面的内容,包括信息在计算机内部的表示方法、数据元素之间的结构关系,以及有效的信息处理方法。此外,书中还描述了编程在模拟、数值方法、符号计算、软件与系统设计等方面的初级应用。此第3版增加了数十项简单但重要的算法和技术,并根据当前研究发展趋势在数学预备知识方面做了大量修改。一起来看看 《计算机程序设计艺术(第1卷)》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试