
本文基于spring-boot-starter-data-jpa:2.7.17分析
SpringBoot 里集成Jpa自动配置是如何处理的
通过分析SpringBoot 自动配置核心源码可以找到JpaRepositoriesRegistrar类,这个类的父类是抽象类AbstractRepositoryConfigurationSourceSupport。 抽象类AbstractRepositoryConfigurationSourceSupport 上面写了一段注释:用来自动配置Spring Data Repositories- class JpaRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {
-
- }
复制代码
这个类同时实现了4个Spring核心接口
ImportBeanDefinitionRegistrar
BeanFactoryAware
ResourceLoaderAware
EnvironmentAware
这4个接口里面,最核心的接口是ImportBeanDefinitionRegistrar, 经常看Spring源码对这个接口肯定不陌生,Spring容器启动时会调用该接口,用于动态注册BeanDefintion,允许你在应用程序上下文启动时以编程的方式定义BeanDefinition。 当实现ImportBeanDefinitionRegistrar时,需要实现其中的registerBeanDefinitions方法,这个方法允许以编程的方式注册BeanDefintion,可以根据条件、配置或者其他逻辑来动态决定要注册那些Bean。
ImportBeanDefinitionRegistrar通常和Import注解一起使用,可以在一个配置类上使用Import注解,将一个实现了ImportBeanDefinitionRegistrar接口的类指定为要注册为Bean定义的来源,在ImportBeanDefinitionRegistrar实现类中,你可以根据需要注册一个或多个BeanDefintion,然后这些Bean就可以在Spring容器中使用。- public abstract class AbstractRepositoryConfigurationSourceSupport
- implements ImportBeanDefinitionRegistrar, BeanFactoryAware, ResourceLoaderAware, EnvironmentAware {
- //这里我删除了成员变量和其他方法,留下这两个核心方法
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
- BeanNameGenerator importBeanNameGenerator) {
- RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(
- getConfigurationSource(registry, importBeanNameGenerator), this.resourceLoader, this.environment);
- //这里声明了委托类 RepositoryConfigurationDelegate,
- //进一步调用了其 registerRepositoriesIn 方法
- delegate.registerRepositoriesIn(registry, getRepositoryConfigurationExtension());
- }
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- registerBeanDefinitions(importingClassMetadata, registry, null);
- }
- }
复制代码 接下来看RepositoryConfigurationDelegate类的核心方法registerRepositoriesIn- /**
- * registry也就是这里用到的是Spring容器DefaultListableBeanFactory
- * extension 也就是实现类JpaRepositoryConfigExtension实例
- * **/
- public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension) {
- extension.registerBeansForRoot(registry, configurationSource);
- RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension,
- configurationSource, resourceLoader, environment);
- List<BeanComponentDefinition> definitions = new ArrayList<>();
- ApplicationStartup startup = getStartup(registry);
- StartupStep repoScan = startup.start("spring.data.repository.scanning");
- repoScan.tag("dataModule", extension.getModuleName());
- repoScan.tag("basePackages",
- () -> configurationSource.getBasePackages().stream().collect(Collectors.joining(", ")));
- //关键代码1: 这里会找到所有的自定义的Repository, 比如我这个demo里的BookRepository, FilmRepository
- Collection<RepositoryConfiguration<RepositoryConfigurationSource>> configurations = extension
- .getRepositoryConfigurations(configurationSource, resourceLoader, inMultiStoreMode);
- Map<String, RepositoryConfiguration<?>> configurationsByRepositoryName = new HashMap<>(configurations.size());
- for (RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration : configurations) {
- configurationsByRepositoryName.put(configuration.getRepositoryInterface(), configuration);
- //关键代码2: 这个builder.build方法里就要产生JpqRepositoryFactoryBean这个对象了
- BeanDefinitionBuilder definitionBuilder = builder.build(configuration);
- extension.postProcess(definitionBuilder, configurationSource);
- if (isXml) {
- extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource) configurationSource);
- } else {
- extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
- }
- //关键代码3: 创建出来beanDefinition
- //1. 这里的beanDefinition的实例化对象类型是RootBeanDefinition
- //2. beanDefinition对象的beanClass是JpaRepositoryFactoryBean 这一步很重要,因为后面从Spring容器中提取时就是这个类
- AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
- beanDefinition.setResourceDescription(configuration.getResourceDescription());
- //beanName也就是自定义的repository, 比如bookRepository
- String beanName = configurationSource.generateBeanName(beanDefinition);
- //给当前beanDefinition设置一个属性,key是常量字符串"factoryBeanObjectType",value值是repository接口全限定名com.codingbetter.jpa.bookRepository
- beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, configuration.getRepositoryInterface());
- //关键代码4: 这里会把自定义的Repository注册到Spring容器中
- registry.registerBeanDefinition(beanName, beanDefinition);
- definitions.add(new BeanComponentDefinition(beanDefinition, beanName));
- }
- potentiallyLazifyRepositories(configurationsByRepositoryName, registry, configurationSource.getBootstrapMode());
- repoScan.tag("repository.count", Integer.toString(configurations.size()));
- repoScan.end();
- return definitions;
- }
复制代码  
OK, 看了这几个代码片段后,也就能回答上面第二个问题了。
那些JpaRepository里没有实现的查询方法,仅靠约定就能实现的是什么原理?
- /**
- * RepositoryFactoryBeanSupport#afterPropertiesSet
- */
- public void afterPropertiesSet() {
- //创建RepositoryFactorySupport, 这个方法在子类JpaRepositoryFactoryBean中实现,父类中只声明了抽象方法名称,交给子类实现
- //子类创建并返回JpaRepositoryFactory类
- //也就是this.factory就是JpaRepositoryFactory实例化类型
- 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);
- this.repositoryFactoryCustomizers.forEach(customizer -> customizer.customize(this.factory));
- RepositoryFragments customImplementationFragment = customImplementation //
- .map(RepositoryFragments::just) //
- .orElseGet(RepositoryFragments::empty);
- RepositoryFragments repositoryFragmentsToUse = this.repositoryFragments //
- .orElseGet(RepositoryFragments::empty) //
- .append(customImplementationFragment);
- this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);
- //关键代码: 这里就会创建SimpleJpaRepository
- //Lazy.of()的参数是委托java.util.function.Supplier
- //这里会调用JpaRepositoryFactory#getRepository()
- this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));
- this.mappingContext.ifPresent(it -> it.getPersistentEntity(repositoryMetadata.getDomainType()));
- if (!lazyInit) {
- //这里的repository是一个Lazy类型,而在上面Lazy中,入参,通过factory.getRepsitory中保存了
- //SimpleJpaRepository引用,所以这里的this.repository.get就是返回SimpleJpaRepository
- this.repository.get();
- }
- }
复制代码 当我们在repo接口里按照契约定义这两个方法,那么jpa就帮我们实现了,那么jpa是怎么帮我们实现呢,答案是AbstractJpaQuery在做。
AbstractJpaQuery抽象类相关实现类

前面注入SimpleJpaRepository类时, RepositoryFactorySupport.getRepository方法里注入了两个关键的拦截器和查询有关,分别是QueryExecutorMethodInterceptor和ImplementationMethodExecutionInterceptor- /**
- * RepositoryFactorySupport#getRepository
- * 第一个参数也就是我们自定义的bookRepository全路径
- */
- public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {
- ApplicationStartup applicationStartup = getStartup();
- StartupStep repositoryInit = onEvent(applicationStartup, "spring.data.repository.init", repositoryInterface);
- repositoryBaseClass.ifPresent(it -> repositoryInit.tag("baseClass", it.getName()));
- StartupStep repositoryMetadataStep = onEvent(applicationStartup, "spring.data.repository.metadata",
- repositoryInterface);
- RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface);
- repositoryMetadataStep.end();
- StartupStep repositoryCompositionStep = onEvent(applicationStartup, "spring.data.repository.composition",
- repositoryInterface);
- repositoryCompositionStep.tag("fragment.count", String.valueOf(fragments.size()));
- RepositoryComposition composition = getRepositoryComposition(metadata, fragments);
- //关键代码1:这一步指定了repositoryBaseClass为SimpleJpaRepository
- RepositoryInformation information = getRepositoryInformation(metadata, composition);
- repositoryCompositionStep.tag("fragments", () -> {
- StringBuilder fragmentsTag = new StringBuilder();
- for (RepositoryFragment<?> fragment : composition.getFragments()) {
- if (fragmentsTag.length() > 0) {
- fragmentsTag.append(";");
- }
- fragmentsTag.append(fragment.getSignatureContributor().getName());
- fragmentsTag.append(fragment.getImplementation().map(it -> ":" + it.getClass().getName()).orElse(""));
- }
- return fragmentsTag.toString();
- });
- repositoryCompositionStep.end();
- StartupStep repositoryTargetStep = onEvent(applicationStartup, "spring.data.repository.target", repositoryInterface);
-
- //关键代码2:看到这句代码是不是很熟悉,这里target就是SimpleJpaRepository
- //getTargetRepository方法在子类JpaRepositoryFactory中实现
- Object target = getTargetRepository(information);
- repositoryTargetStep.tag("target", target.getClass().getName());
- repositoryTargetStep.end();
- RepositoryComposition compositionToUse = composition.append(RepositoryFragment.implemented(target));
- validate(information, compositionToUse);
- StartupStep repositoryProxyStep = onEvent(applicationStartup, "spring.data.repository.proxy", repositoryInterface);
-
- //关键代码3:创建代理,设置Target和Interface
- ProxyFactory result = new ProxyFactory();
- result.setTarget(target);
- result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);
- if (MethodInvocationValidator.supports(repositoryInterface)) {
- result.addAdvice(new MethodInvocationValidator());
- }
- result.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
- if (!postProcessors.isEmpty()) {
- StartupStep repositoryPostprocessorsStep = onEvent(applicationStartup, "spring.data.repository.postprocessors",
- repositoryInterface);
- postProcessors.forEach(processor -> {
- StartupStep singlePostProcessor = onEvent(applicationStartup, "spring.data.repository.postprocessor",
- repositoryInterface);
- singlePostProcessor.tag("type", processor.getClass().getName());
- processor.postProcess(result, information);
- singlePostProcessor.end();
- });
- repositoryPostprocessorsStep.end();
- }
- if (DefaultMethodInvokingMethodInterceptor.hasDefaultMethods(repositoryInterface)) {
- result.addAdvice(new DefaultMethodInvokingMethodInterceptor());
- }
- Optional<QueryLookupStrategy> queryLookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,
- evaluationContextProvider);
- result.addAdvice(new QueryExecutorMethodInterceptor(information, getProjectionFactory(), queryLookupStrategy,
- namedQueries, queryPostProcessors, methodInvocationListeners));
- result.addAdvice(new ImplementationMethodExecutionInterceptor(information, compositionToUse, methodInvocationListeners));
- //关键代码4:从代理里获取repository, 也就是SimpleJpaRepository
- T repository = (T) result.getProxy(classLoader);
- repositoryProxyStep.end();
- repositoryInit.end();
- return repository;
- }
复制代码QueryExecutorMethodInterceptor拦截器的构造函数
- /***
- * RepositoryFactorySupport#getRepositoryInformation
- */
- private RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata,
- RepositoryComposition composition) {
- RepositoryInformationCacheKey cacheKey = new RepositoryInformationCacheKey(metadata, composition);
- return repositoryInformationCache.computeIfAbsent(cacheKey, key -> {
- //这一步调用getRepositoryBaseClass, 而这个方法会由子类重写
- Class<?> baseClass = repositoryBaseClass.orElse(getRepositoryBaseClass(metadata));
- return new DefaultRepositoryInformation(metadata, baseClass, composition);
- });
- }
- /**
- * JpaRepositoryFactory#getRepositoryBaseClass
- * 这一步创建了SimpleJpaRepository
- */
- protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
- return SimpleJpaRepository.class;
- }
复制代码 这里PartTreeJpaQuery类里有个关键类PartTree, 在这个类里会看到根据契约find, count, exists去查询数据, 会根据正则表达式去匹配查询方法, 对吧,看到这些方法是不是就很熟悉了。
PartTreeJpaQuery
- public interface BookRepository extends JpaRepository<Book, Integer> {
- List<Book> findByName(String name);
- List<Book> findByAuthor(String author);
- }
复制代码PartTree
- public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {
- Optional<QueryLookupStrategy> queryLookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,
- evaluationContextProvider);
- result.addAdvice(new QueryExecutorMethodInterceptor(information, getProjectionFactory(), queryLookupStrategy, namedQueries, queryPostProcessors, methodInvocationListeners));
- result.addAdvice(new ImplementationMethodExecutionInterceptor(information, compositionToUse, methodInvocationListeners));
- T repository = (T) result.getProxy(classLoader);
- repositoryProxyStep.end();
- repositoryInit.end();
- return repository;
- }
复制代码AbstractJpaQuery#execute
- private final Map<Method, RepositoryQuery> queries;
- public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformation,
- ProjectionFactory projectionFactory,
- Optional<QueryLookupStrategy> queryLookupStrategy,
- NamedQueries namedQueries,
- List<QueryCreationListener<?>> queryPostProcessors,
- List<RepositoryMethodInvocationListener> methodInvocationListeners) {
- this.repositoryInformation = repositoryInformation;
- this.namedQueries = namedQueries;
- this.queryPostProcessors = queryPostProcessors;
- this.invocationMulticaster = methodInvocationListeners.isEmpty() ? NoOpRepositoryInvocationMulticaster.INSTANCE
- : new DefaultRepositoryInvocationMulticaster(methodInvocationListeners);
- this.resultHandler = new QueryExecutionResultHandler(RepositoryFactorySupport.CONVERSION_SERVICE);
-
- /***
- **这个queries是一个map数组,保存了你的自定义查询方法。
- **这里也就能明白RepositoryQuery的设计, 一个自定义方法就代表一个RepositoryQuery
- */
- this.queries = queryLookupStrategy
- .map(it -> mapMethodsToQuery(repositoryInformation, it, projectionFactory)) //
- .orElse(Collections.emptyMap());
- }
复制代码
OK 看到这里第三个问题也就知道来龙去脉了,再说一句,PartTreeJpaQuery是针对在方法头上未标注Query注解的方法,它是用jpa根据方法去识别并转化成SQL方法去执行。
总结
接触jpa时间不长,里面一些来龙去脉还在研究和摸索中,如果有描述不正确的地方,可以留言讨论哦。
参考链接
https://xie.infoq.cn/article/24c7c7874e31f9f057f80ff40
https://www.cnblogs.com/sword-successful/p/14337507.html
https://zhuanlan.zhihu.com/p/344630578
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |