【源码】Spring Data JPA原理解析之Repository的自动注入(一)

  Spring Data JPA系列

1、SpringBoot集成JPA及基本使用

2、Spring Data JPA Criteria查询、部分字段查询

3、Spring Data JPA数据批量插入、批量更新真的用对了吗

4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作

5、Spring Data JPA自定义Id生成策略、复合主键配置、Auditing使用

6、【源码】Spring Data JPA原理解析之Repository的自动注入(一)

7、【源码】Spring Data JPA原理解析之Repository的自动注入(二)

8、【源码】Spring Data JPA原理解析之Repository执行过程及SimpleJpaRepository源码

9、【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(一)

10、【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(二)

11、【源码】Spring Data JPA原理解析之Repository自定义方法添加@Query注解的执行原理

12、【源码】SpringBoot事务注册原理

13、【源码】Spring Data JPA原理解析之事务注册原理

前言

前面5篇分享了Spring Data JPA的用法,在Spring Data JPA中的Repository类不需要添加任何注解,为何就能够自动注入到Spring的IOC容器中呢?为何只需要继承JpaRepository或JJpaRepositoryImplementation接口,就能够使用系统的CRUD接口?为何只需要在接口方法中使用@Query注解,就能够实现对应数据库表的操作呢?让我们一起从源码中寻找答案吧!本篇基于Spring-boot-2.7.x的源码分析。

JpaRepositoriesAutoConfiguration

在Spring Boot框架中,通常通过XxxAutoConfiguration类自动注入某个插件的功能,Spring Data JPA也是如此。通常XxxAutoConfiguration类是在对应插件的starter包里面的,而Spring Data JPA的starter包下的META-INF并没有对应的spring.factories文件。如下:

搜索引用该类的地方:

说明JpaRepositoriesAutoConfiguration是spring boot自带的,但为何要使用Spring Data JPA的时候,还需要引入spring-boot-starter-data-jpa依赖呢?以下为JpaRepositoriesAutoConfiguration的代码:

package org.springframework.boot.autoconfigure.data.jpa;

@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
@ConditionalOnBean(DataSource.class)
// 需要有JpaRepository类
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class })
@ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "enabled", havingValue = "true",
		matchIfMissing = true)
// 自动引入内部类JpaRepositoriesImportSelector,在JpaRepositoriesImportSelector中,引入JpaRepositoriesRegistrar
@Import(JpaRepositoriesImportSelector.class)
public class JpaRepositoriesAutoConfiguration {

	// 省略其他代码

	static class JpaRepositoriesImportSelector implements ImportSelector {

		private static final boolean ENVERS_AVAILABLE = ClassUtils.isPresent(
				"org.springframework.data.envers.repository.config.EnableEnversRepositories",
				JpaRepositoriesImportSelector.class.getClassLoader());

		@Override
		public String[] selectImports(AnnotationMetadata importingClassMetadata) {
			return new String[] { determineImport() };
		}

		private String determineImport() {
			// 自定引入JpaRepositoriesRegistrar
			return ENVERS_AVAILABLE ? EnversRevisionRepositoriesRegistrar.class.getName()
					: JpaRepositoriesRegistrar.class.getName();
		}

	}

}

JpaRepositoriesAutoConfiguration要自动引入,条件是需要有JpaRepository类,而该类是在spring-data-jpa包下,所以需要额外导入spring-boot-starter-data-jpa依赖。

JpaRepositoriesAutoConfiguration自动注入时,会自动注入JpaRepositoriesImportSelector,该类实现了ImportSelector接口。Spring的配置类解析的时候,会执行ConfigurationClassParser.processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports),在该方法中,判断importCandidates是否继承于ImportSelector接口,如果是,调用ImportSelector的selectImports()方法,获取需要额外自动加入容器的类。

在JpaRepositoriesImportSelector中的selectImports()方法中,返回JpaRepositoriesRegistrar.class.getName(),自动注入JpaRepositoriesRegistrar类。

JpaRepositoriesRegistrar源码如下:

package org.springframework.boot.autoconfigure.data.jpa;

class JpaRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {

	private BootstrapMode bootstrapMode = null;

	/**
	 * 指定@EnableJpaRepositories注解,所以在启动类中可以不添加该注解
	 * @return
	 */
	@Override
	protected Class<? extends Annotation> getAnnotation() {
		return EnableJpaRepositories.class;
	}

	/**
	 * 指定EnableJpaRepositoriesConfiguration配置类
	 * @return
	 */
	@Override
	protected Class<?> getConfiguration() {
		return EnableJpaRepositoriesConfiguration.class;
	}

	/**
	 * 指定RepositoryConfigurationExtension配置扩展
	 * @return
	 */
	@Override
	protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
		return new JpaRepositoryConfigExtension();
	}

	@Override
	protected BootstrapMode getBootstrapMode() {
		return (this.bootstrapMode == null) ? BootstrapMode.DEFAULT : this.bootstrapMode;
	}

	@Override
	public void setEnvironment(Environment environment) {
		super.setEnvironment(environment);
		configureBootstrapMode(environment);
	}

	private void configureBootstrapMode(Environment environment) {
		String property = environment.getProperty("spring.data.jpa.repositories.bootstrap-mode");
		if (StringUtils.hasText(property)) {
			this.bootstrapMode = BootstrapMode.valueOf(property.toUpperCase(Locale.ENGLISH));
		}
	}

	@EnableJpaRepositories
	private static class EnableJpaRepositoriesConfiguration {

	}

}

父类AbstractRepositoryConfigurationSourceSupport的核心源码代码如下:

package org.springframework.boot.autoconfigure.data;

/**
 * 实现ImportBeanDefinitionRegistrar接口
 */
public abstract class AbstractRepositoryConfigurationSourceSupport
		implements ImportBeanDefinitionRegistrar, BeanFactoryAware, ResourceLoaderAware, EnvironmentAware {

	private ResourceLoader resourceLoader;

	private BeanFactory beanFactory;

	private Environment environment;

	/**
	 * ImportBeanDefinitionRegistrar接口的方法,在ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass() ->
	 * loadBeanDefinitionsFromRegistrars()【执行实现ImportBeanDefinitionRegistrar接口的类的
	 * registerBeanDefinitions()方法,注册其他bean】
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {
		RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(
				getConfigurationSource(registry, importBeanNameGenerator), this.resourceLoader, this.environment);
		// 子类JpaRepositoriesRegistrar.getRepositoryConfigurationExtension()返回JpaRepositoryConfigExtension
		// 自动注入JpaRepositoryConfigExtension对象
		delegate.registerRepositoriesIn(registry, getRepositoryConfigurationExtension());
	}

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		registerBeanDefinitions(importingClassMetadata, registry, null);
	}

	private AnnotationRepositoryConfigurationSource getConfigurationSource(BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {
		AnnotationMetadata metadata = AnnotationMetadata.introspect(getConfiguration());
		return new AutoConfiguredAnnotationRepositoryConfigurationSource(metadata, getAnnotation(), this.resourceLoader,
				this.environment, registry, importBeanNameGenerator) {
		};
	}

	
	protected abstract RepositoryConfigurationExtension getRepositoryConfigurationExtension();

	// 省略其他

}

通过以上的源码,Spring中会自动注入JpaRepositoryConfigExtension类。

JpaRepositoryConfigExtension

JpaRepositoryConfigExtension为Jpa repository配置扩展类,类的结构如下:

2.1 RepositoryConfigurationExtension的源码如下:

package org.springframework.data.repository.config;

/**
 * SPI实现对存储库bean定义注册过程的特定于存储库的扩展
 */
public interface RepositoryConfigurationExtension {
    /**
	 * 在所有Spring Data模块中唯一标识模块的字符串。不得包含任何空格。模块的描述性名称小写,且空格转化为“-”
	 */
	default String getModuleIdentifier() {

		return getModuleName().toLowerCase(Locale.ENGLISH).replace(' ', '-');
	}

	/**
	 * 返回模块的描述性名称
	 * @return
	 */
	String getModuleName();

	/**
	 * 返回{@link BeanRegistryAotProcessor}类型,该类型负责在本机运行时提供Spring Data Repository基础结构组件所需的AOT/本机配置。
	 * @return
	 */
	@NonNull
	default Class<? extends BeanRegistrationAotProcessor> getRepositoryAotProcessor() {
		return RepositoryRegistrationAotProcessor.class;
	}

	/**
	 * 通过给定的RepositoryConfigurationSource获得所有的RepositoryConfiguration对象
	 * @param configSource RepositoryConfigurationSource对象,封装了repository配置的源(XML/Annotation)
	 * @param loader 用于加载资源
	 * @param strictMatchesOnly 是否仅返回严格匹配的repository。为true将导致检查所处理的存储库接口和域类型是否由当前存储管理
	 */
	<T extends RepositoryConfigurationSource> Collection<RepositoryConfiguration<T>> getRepositoryConfigurations(
			T configSource, ResourceLoader loader, boolean strictMatchesOnly);

	/**
	 * 返回Spring Data命名查询的默认位置
	 */
	String getDefaultNamedQueryLocation();

	/**
	 * 获取要使用的repository工厂类的名字
	 */
	String getRepositoryFactoryBeanClassName();

	/**
	 * 回调以注册{@literal repositories}根节点的其他bean定义。这通常包括必须独立于要创建的存储库数量设置一次的bean。
	 * 将在注册任何存储库bean定义之前调用。
	 */
	void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource configurationSource);

	/**
	 * 回调用于对{@link BeanDefinition}进行后处理,并在必要时调整配置。
	 */
	void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSource config);

	/**
	 * 回调用于对从注释构建的{@link BeanDefinition}进行后处理,并在必要时调整配置。
	 */
	void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource config);

	/**
	 * 回调用于对从XML构建的{@link BeanDefinition}进行后处理,并在必要时调整配置。
	 */
	void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config);
}

2.2 RepositoryConfigurationExtensionSupport核心源码如下:

/**
 * RepositoryConfigurationExtension的基本实现,以简化接口的实现。将根据实现者提供的模块前缀默认命名查询位置
 * (请参见{getModulePrefix())。截断后处理方法,因为默认情况下可能不需要它们。
 */
public abstract class RepositoryConfigurationExtensionSupport implements RepositoryConfigurationExtension {

	@Override
	public String getModuleName() {
		return StringUtils.capitalize(getModulePrefix());
	}

	public <T extends RepositoryConfigurationSource> Collection<RepositoryConfiguration<T>> getRepositoryConfigurations(
			T configSource, ResourceLoader loader) {
		return getRepositoryConfigurations(configSource, loader, false);
	}

	/**
	 * 通过给定的RepositoryConfigurationSource获得所有的RepositoryConfiguration对象
	 * @param configSource RepositoryConfigurationSource对象,封装了repository配置的源(XML/Annotation)
	 * @param loader 用于加载资源
	 * @param strictMatchesOnly 是否仅返回严格匹配的repository。为true将导致检查所处理的存储库接口和域类型是否由当前存储管理
	 */
	public <T extends RepositoryConfigurationSource> Collection<RepositoryConfiguration<T>> getRepositoryConfigurations(
			T configSource, ResourceLoader loader, boolean strictMatchesOnly) {

		Assert.notNull(configSource, "ConfigSource must not be null");
		Assert.notNull(loader, "Loader must not be null");

		Set<RepositoryConfiguration<T>> result = new HashSet<>();
		// configSource.getCandidates(loader)返回所有定义的Repository接口类
		for (BeanDefinition candidate : configSource.getCandidates(loader)) {

			RepositoryConfiguration<T> configuration = getRepositoryConfiguration(candidate, configSource);
			// 获取Repository接口类,如GoodsRepository.class
			Class<?> repositoryInterface = loadRepositoryInterface(configuration,
					getConfigurationInspectionClassLoader(loader));

			if (repositoryInterface == null) {
				result.add(configuration);
				continue;
			}

			// 解析接口的Repository元信息,保存对应Repository<T, ID>中T及ID的类型元信息
			RepositoryMetadata metadata = AbstractRepositoryMetadata.getMetadata(repositoryInterface);
			// 判断是否为Repository
			boolean qualifiedForImplementation = !strictMatchesOnly || configSource.usesExplicitFilters()
					|| isStrictRepositoryCandidate(metadata);

			if (qualifiedForImplementation && useRepositoryConfiguration(metadata)) {
				result.add(configuration);
			}
		}

		return result;
	}

}

该类最核心的方法是getRepositoryConfigurations()方法,通过该方法,执行configSource.getCandidates()从configSource获取要自动注入Spring容器的Repository Bean。

2.2.1 通过configSource.getCandidates()方法,获取Repository Bean

代码在RepositoryConfigurationSourceSupport中实现,代码如下:

public abstract class RepositoryConfigurationSourceSupport implements RepositoryConfigurationSource {

	/**
	 * 返回要为其创建存储库实例的存储库接口的源BeanDefinition
	 */
	@Override
	public Streamable<BeanDefinition> getCandidates(ResourceLoader loader) {

		// 定义一个RepositoryComponentProvider对象,传入包含的过滤器。
		// getIncludeFilters()在子类中实现,
		// 子类有AnnotationRepositoryConfigurationSource和XmlRepositoryConfigurationSource
		RepositoryComponentProvider scanner = new RepositoryComponentProvider(getIncludeFilters(), registry);
		scanner.setConsiderNestedRepositoryInterfaces(shouldConsiderNestedRepositories());
		scanner.setEnvironment(environment);
		scanner.setResourceLoader(loader);
		// 添加排除的类型过滤器
		getExcludeFilters().forEach(scanner::addExcludeFilter);

		return Streamable.of(() -> getBasePackages().stream()//
				// 遍历基础包,根据RepositoryComponentProvider定义时添加的包含filter和排除filter,扫描beanDefinition对象
				.flatMap(it -> scanner.findCandidateComponents(it).stream()));
	}

}

2.2.1.1 在该方法中,先new一个RepositoryComponentProvider对象,其中的getIncludeFilter()和getExcludeFilters()分别用于添加扫描时要包含和排除的过滤器。对于使用注解实现的JPA,实现在子类AnnotationRepositoryConfigurationSource,该类主要职责是解析@EnableJpaRepositories注解的信息,其中的包含和排除的过滤器就是在该注解中配置的includeFilters和excludeFilters。

RepositoryComponentProvider代码如下:

/**
 * 自定义类路径扫描候选组件提供程序ClassPathScanningCandidateComponentProvider,扫描给定基本接口的接口类。
 * 不使用ClassPathScanningCandidateComponentProvider中的默认过滤器。 
 * 跳过添加@NoRepositoryBean的接口
 */
class RepositoryComponentProvider extends ClassPathScanningCandidateComponentProvider {

	private boolean considerNestedRepositoryInterfaces;
	private BeanDefinitionRegistry registry;

	public RepositoryComponentProvider(Iterable<? extends TypeFilter> includeFilters, BeanDefinitionRegistry registry) {
        // 父类的构造方法中传入false,即不适用默认的过滤器。即仅使用RepositoryComponentProvider添加的过滤器
		super(false);

		Assert.notNull(includeFilters, "Include filters must not be null");
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

		// DefaultListableBeanFactory对象
		this.registry = registry;
		// 添加指定的类型过滤器
		if (includeFilters.iterator().hasNext()) {
			for (TypeFilter filter : includeFilters) {
				addIncludeFilter(filter);
			}
		} else {
			// 如果没有类型过滤器,则添加Repository接口的类型过滤器以及添加@RepositoryDefinition注解的类型过滤器
			super.addIncludeFilter(new InterfaceTypeFilter(Repository.class));
			// AnnotationTypeFilter类似InterfaceTypeFilter类,前面是用于过滤特定注解,后面用于过滤特定接口
			super.addIncludeFilter(new AnnotationTypeFilter(RepositoryDefinition.class, true, true));
		}
		// 不扫描添加@NoRepositoryBean注解的类
		addExcludeFilter(new AnnotationTypeFilter(NoRepositoryBean.class));
	}

	/**
	 * 重写父类的方法,在添加入参的TypeFilter以外,还需要同时满足继承Repository,或添加了@RepositoryDefinition注解
	 */
	@Override
	public void addIncludeFilter(TypeFilter includeFilter) {

		List<TypeFilter> filterPlusInterface = new ArrayList<>(2);
		filterPlusInterface.add(includeFilter);
		filterPlusInterface.add(new InterfaceTypeFilter(Repository.class));
		// 添加TypeFilter及继承Repository的类型过滤器
		super.addIncludeFilter(new AllTypeFilter(filterPlusInterface));

		List<TypeFilter> filterPlusAnnotation = new ArrayList<>(2);
		filterPlusAnnotation.add(includeFilter);
		filterPlusAnnotation.add(new AnnotationTypeFilter(RepositoryDefinition.class, true, true));
		// 添加TypeFilter及添加@RepositoryDefinition注解
		super.addIncludeFilter(new AllTypeFilter(filterPlusAnnotation));
	}

	/**
	 * 自定义存储库接口检测并触发对它们的注释检测
	 */
	@Override
	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
		// 是非存储库接口,不是Repository.class
		boolean isNonRepositoryInterface = !ClassUtils.isGenericRepositoryInterface(beanDefinition.getBeanClassName());
		// 不是顶级类型
		boolean isTopLevelType = !beanDefinition.getMetadata().hasEnclosingClass();
		// 是考虑嵌套存储库
		boolean isConsiderNestedRepositories = isConsiderNestedRepositoryInterfaces();

		return isNonRepositoryInterface && (isTopLevelType || isConsiderNestedRepositories);
	}

	@Override
	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		// 查找所有的Repository类
		Set<BeanDefinition> candidates = super.findCandidateComponents(basePackage);

		for (BeanDefinition candidate : candidates) {
			if (candidate instanceof AnnotatedBeanDefinition) {
				// 处理通用注解,解析@Lazy、@Primary、@DependOn、@Role、@Description中的value,添加到BeanDefinition中
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
		}

		return candidates;
	}

	/**
	 * 接口类型过滤器,对应类必须的接口,且为构造方法传入的targetType或targetType的子类。
	 * 在super.match()中会遍历继承树,判断是否为targetType,即父类为targetType
	 */
	private static class InterfaceTypeFilter extends AssignableTypeFilter {

		public InterfaceTypeFilter(Class<?> targetType) {
			super(targetType);
		}

		/*
		 * 返回对应的类是否为接口,且为构造方法传入的targetType或targetType的子类。
		 * 在super.match()中会遍历继承树,判断是否为targetType,即父类为targetType
		 */
		@Override
		public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
				throws IOException {

			return metadataReader.getClassMetadata().isInterface() && super.match(metadataReader, metadataReaderFactory);
		}
	}

	/**
	 * 匹配所有的类型过滤器
	 */
	private static class AllTypeFilter implements TypeFilter {

		private final List<TypeFilter> delegates;

		public AllTypeFilter(List<TypeFilter> delegates) {

			Assert.notNull(delegates, "TypeFilter deleages must not be null");
			this.delegates = delegates;
		}

		/*
		 * 遍历所有的TypeFilter,只要一个不匹配,则返回false
		 */
		public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
				throws IOException {

			for (TypeFilter filter : delegates) {
				if (!filter.match(metadataReader, metadataReaderFactory)) {
					return false;
				}
			}

			return true;
		}
	}
}

在构造方法中,由于没有添加@EnableJpaRepositories注解注解,也就没有添加对应的includeFilters,所以走else分支,添加了Repository接口的类型过滤器以及@RepositoryDefinition注解的类型过滤器。然后添加了@NoRepositoryBean注解的排除过滤器。即会扫描实现Repository接口或添加@RepositoryDefinition注解的类,且类中不能添加@NoRepositoryBean注解。

另外,父类ClassPathScanningCandidateComponentProvider的构造方法中,如果传入的值为true,会添加@Component注解类的自动扫描。

2.2.1.2 然后调用RepositoryComponentProvider的findCandidateComponents(it)方法。该方法调用父类ClassPathScanningCandidateComponentProvider的findCandidateComponents()方法。

ClassPathScanningCandidateComponentProvider的代码如下:

package org.springframework.context.annotation;

/**
 * 从基本包中扫描候选组件的组件提供程序。可以使用{@link CandidateComponentsIndex the index}(如果可用)
 * 扫描类路径,否则,通过应用排除(exclude)和包含(include)过滤器来识别候选组件。
 * 特定注解类型过滤器(AnnotationTypeFilter)、可转化的类型过滤器(AssignableTypeFilter,为特定类型的子类)支持
 * CandidateComponentsIndex的筛选:如果指定了任何其他包含筛选器,则会忽略CandidateComponentsIndex,而使用类路径扫描。
 */
public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {

	// 默认资源模式。扫描所有的.class文件
	static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";


	protected final Log logger = LogFactory.getLog(getClass());

	private String resourcePattern = DEFAULT_RESOURCE_PATTERN;

	// 包含的过滤器,满足条件的类会被扫描注册成bean。默认为添加@Component、@Repository、
	// @Service、@Controller、@ManagedBean、@Named注解的类,后面两个需要引入相关依赖
	private final List<TypeFilter> includeFilters = new LinkedList<>();

	// 不包含的过滤器,满足条件的类会被忽略,不扫描
	private final List<TypeFilter> excludeFilters = new ArrayList<>();

	// 运行时环境,可以获取系统变量和配置文件信息
	@Nullable
	private Environment environment;

	// @Conditional条件判断的计算器。@Conditional可以添加在@Bean上,满足@Conditional条件的bean才会被加载到Spring容器中
	@Nullable
	private ConditionEvaluator conditionEvaluator;

	// 资源匹配模式解析器
	@Nullable
	private ResourcePatternResolver resourcePatternResolver;

	// MetadataReader的工厂类,用于读取类文件的元数据
	@Nullable
	private MetadataReaderFactory metadataReaderFactory;

	// 提供对META-INF/spring.components中定义的候选者的访问控制
	@Nullable
	private CandidateComponentsIndex componentsIndex;

	protected ClassPathScanningCandidateComponentProvider() {
	}

	/**
	 * 创建一个标注环境的扫描组件提供器。useDefaultFilters用于指定是否应用默认的过滤器。如果为true,会自动包含对
	 * @Component、@Repository、@Service、@Controller的支持
	 */
	public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters) {
		this(useDefaultFilters, new StandardEnvironment());
	}

	public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
		// 如果为true,调用registerDefaultFilters(),注册默认的过滤器,包含对
		// @Component、@Repository、@Service、@Controller的支持
		if (useDefaultFilters) {
			registerDefaultFilters();
		}
		setEnvironment(environment);
		setResourceLoader(null);
	}

	/**
	 * 添加一个包含的类型过滤器,用于指定对应类型的组件在被包含的扫描结果中
	 */
	public void addIncludeFilter(TypeFilter includeFilter) {
		this.includeFilters.add(includeFilter);
	}

	/**
	 * 添加一个排除的类型过滤器,用于指定对应类型的组件不在被包含的扫描结果中
	 */
	public void addExcludeFilter(TypeFilter excludeFilter) {
		this.excludeFilters.add(0, excludeFilter);
	}

	/**
	 * 重置过滤器,清空包含和排除的过滤器集合,重写注册默认的类型过滤器
	 */
	public void resetFilters(boolean useDefaultFilters) {
		this.includeFilters.clear();
		this.excludeFilters.clear();
		if (useDefaultFilters) {
			registerDefaultFilters();
		}
	}

	/**
	 * 注册默认的过滤器,包含对@Component、@Repository、@Service、@Controller、@ManagedBean、@Named的过滤
	 */
	@SuppressWarnings("unchecked")
	protected void registerDefaultFilters() {
		// 添加@Component过滤,@Repository、@Service、@Controller都添加了@Component,
		// 也会过滤@Repository、@Service、@Controller
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
			// 添加@ManagedBean过滤
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
			logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
		}
		try {
			// 添加@Named过滤
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
			logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}

	/**
	 * 设置用于加载资源的ResourceLoader实例
	 */
	@Override
	public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
		// 如果resourceLoader实现了ResourcePatternResolver,直接返回,否则创建一个PathMatchingResourcePatternResolver对象
		this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
		this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
		// 读取配置文件META-INF/spring.components中的信息,如果有信息,创建一个CandidateComponentsIndex对象并保存配置信息返回
		this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
	}

	/**
	 * 设置用于创建MetadataReader实例的工厂。允许自定义如何读取类的元数据
	 */
	public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
		this.metadataReaderFactory = metadataReaderFactory;
	}

	/**
	 * 返回一个带缓存功能的MetadataReaderFactory工厂,可以将某个类对应的MetadataReader进行缓存
	 * @return
	 */
	public final MetadataReaderFactory getMetadataReaderFactory() {
		if (this.metadataReaderFactory == null) {
			this.metadataReaderFactory = new CachingMetadataReaderFactory();
		}
		return this.metadataReaderFactory;
	}

	/**
	 * 扫描指定包及其子包的候选组件
	 */
	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		// 如果componentsIndex不为null,即META-INF/spring.components中有配置信息,
		// 且include过滤器都支持@Indexed注解,从配置中扫描
		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
		}
		else {
			// 扫描特定包
			return scanCandidateComponents(basePackage);
		}
	}

	/**
	 * 判断包含的过滤器是否支持都支持@Indexed注解,都支持返回true,否则返回false
	 */
	private boolean indexSupportsIncludeFilters() {
		for (TypeFilter includeFilter : this.includeFilters) {
			if (!indexSupportsIncludeFilter(includeFilter)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 确认指定的filter是否支持@Indexed注解或者是javax.开头的注解
	 */
	private boolean indexSupportsIncludeFilter(TypeFilter filter) {
		if (filter instanceof AnnotationTypeFilter) {
			Class<? extends Annotation> annotation = ((AnnotationTypeFilter) filter).getAnnotationType();
			return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotation) ||
					annotation.getName().startsWith("javax."));
		}
		if (filter instanceof AssignableTypeFilter) {
			Class<?> target = ((AssignableTypeFilter) filter).getTargetType();
			return AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, target);
		}
		return false;
	}

	/**
	 * 获取TypeFilter的原型,即名称
	 */
	@Nullable
	private String extractStereotype(TypeFilter filter) {
		if (filter instanceof AnnotationTypeFilter) {
			return ((AnnotationTypeFilter) filter).getAnnotationType().getName();
		}
		if (filter instanceof AssignableTypeFilter) {
			return ((AssignableTypeFilter) filter).getTargetType().getName();
		}
		return null;
	}

	private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			Set<String> types = new HashSet<>();
			for (TypeFilter filter : this.includeFilters) {
				// 获取filter的名称。全限定名,包名加类名,如:org.springframework.stereotype.Component
				String stereotype = extractStereotype(filter);
				if (stereotype == null) {
					throw new IllegalArgumentException("Failed to extract stereotype from " + filter);
				}
				// 查找basePackage包下所有stereotype类型的类的名称
				types.addAll(index.getCandidateTypes(basePackage, stereotype));
			}
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (String type : types) {
				// 获取类中元数据读取器,包含类的资源信息、类元模型、类中添加的注解元模型
				MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
				// 判断给定的MetadataReader是否是一个候选组件。该组件不在排除过滤器中,
				//是在包含的过滤器中,且满足@Conditional条件或没有@Conditional
				if (isCandidateComponent(metadataReader)) {
					ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
					sbd.setSource(metadataReader.getResource());
					// 确定给定的bean定义是否符合候选条件。默认实现检查类是否不是接口,是否不依赖于封闭类可以在子类中重写
					if (isCandidateComponent(sbd)) {
						if (debugEnabled) {
							logger.debug("Using candidate component class from index: " + type);
						}
						candidates.add(sbd);
					}
					else {
						if (debugEnabled) {
							logger.debug("Ignored because not a concrete top-level class: " + type);
						}
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because matching an exclude filter: " + type);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// 包的查询路径,如:classpath*:com/jingai/jpa/**/*.class
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			// 获得符合查询条件的所有类的资源
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
						if (isCandidateComponent(metadataReader)) {
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setSource(resource);
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

	protected String resolveBasePackage(String basePackage) {
		return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage));
	}

	/**
	 * 判断给定的MetadataReader是否是一个候选组件。该组件不在排除过滤器中,
	 * 是在包含的过滤器中,且满足@Conditional条件或没有@Conditional
	 */
	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		// 如果在排除的过滤器中,返回false
		for (TypeFilter tf : this.excludeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return false;
			}
		}
		// 如果在包含的过滤器中,满足@Conditional注解的配置要求或没有@Conditional注解,返回true,否则返回false
		for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

	/**
	 * 判断是否满足@Conditional注解的配置要求,如果不满足,返回false。没有添加或满足,返回true
	 */
	private boolean isConditionMatch(MetadataReader metadataReader) {
		if (this.conditionEvaluator == null) {
			this.conditionEvaluator =
					new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
		}
		return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
	}

	/**
	 * 确定给定的bean定义是否符合候选条件。默认实现检查类是否不是接口,是否不依赖于封闭类可以在子类中重写。
	 */
	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
		AnnotationMetadata metadata = beanDefinition.getMetadata();
		// 确定基础类是独立的,即它是顶级类或可以独立于封闭类构造的嵌套类(静态内部类)
		// 返回底层类是否表示具体类,即既不是接口也不是抽象类,或者是抽象类,但添加了@Lockup注解
		return (metadata.isIndependent() && (metadata.isConcrete() ||
				(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
	}

}

在findCandidateComponents()方法中,执行else分支,调用scanCandidateComponents(),扫描特定包下的组件,传入此方法的basePackage的值没有设置的情况下,默认传入的是SpringBoot主方法所在的包。如本Spring Data JPA系列篇章传入的basePackage为com.jingai.jpa。

1)获得packageSearchPath,值为classpath*:com/jingai/jpa/**/*.class,即扫描com.jingai.jpa包及其子包所有class类;

2)遍历class类,获取类对应的MetadataReader。其中MetadataReader用于访问类元数据的简单外观,由ASM{@link org.springframework.ASM.ClassReader}读取。包含类文件资源信息、类元数据、注解元数据;

3)调用isCandidateComponent()方法,判断该组件不在排除excludeFilters过滤器中,是在包含includeFilters的过滤器中,且满足@Conditional条件或没有@Conditional。

结合上面调用构造函数时创建的过滤器可知:

a)默认的ClassPathScanningCandidateComponentProvider,

includeFilters包含添加了@Component、@Repository、@Service、@Controller注解的类【@Repository、@Service、@Controller注解添加了@Component,也会扫描】,会扫描。excludeFilters为空。该默认方式也是Spring默认处理的方式,所以在类中添加上面的注解,即可自动注入到Spring IOC容器;

b)对于RepositoryComponentProvider,继承了ClassPathScanningCandidateComponentProvider,传入构造方法的值为false,不会添加默认的过滤器,只添加了自己的过滤器,includeFilters包含实现了Repository接口、添加@RepositoryDefinition注解的类,会扫描。excludeFilters包含@NoRepositoryBean注解,不会扫描。即只扫描跟JPA的Repository相关的类。

在项目中,Repository实现了JpaRepositoryImplementation或JpaRepository接口,它们都继承了Repository接口。

此处有一个优化点,最好指定Repository所在的包,省得扫描整个SpringBoot启动类所在的包及其子包来获取Repository类;

4)调用isCandidateComponent(),确定给定的bean定义是否符合候选条件。默认实现检查类是否不是接口,是否不依赖于封闭类可以在子类中重写;

通过findCandidateComponents()方法,找出所有满足条件的组件,即bean。

2.2.2 遍历2.2.1中找到的所有满足条件的组件

组件实现Repository接口或添加了@RepositoryDefinition注解,且不能添加@NoRepositoryBean注解的类,调用loadRepositoryInterface()方法,获取Repository接口类;

调用AbstractRepositoryMetadata.getMetadata(repositoryInterface),解析接口的Repository元信息,保存对应Repository<T, ID>中T及ID的类型元信息;

进行元数据判断,此处的strictMatchesOnly为false,所以都会加入到集合中返回;

2.3 JpaRepositoryConfigExtension源码如下

public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport {

	private static final Class<?> PAB_POST_PROCESSOR = PersistenceAnnotationBeanPostProcessor.class;
	private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
	private static final String ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE = "enableDefaultTransactions";
	private static final String JPA_METAMODEL_CACHE_CLEANUP_CLASSNAME = "org.springframework.data.jpa.util.JpaMetamodelCacheCleanup";
	private static final String ESCAPE_CHARACTER_PROPERTY = "escapeCharacter";

	private final Map<Object, String> entityManagerRefs = new LinkedHashMap<>();

	@Override
	public String getModuleName() {
		return "JPA";
	}

	/**
	 * 获取要使用的repository工厂类的名字
	 */
	@Override
	public String getRepositoryFactoryBeanClassName() {
		return JpaRepositoryFactoryBean.class.getName();
	}

	@Override
	protected String getModulePrefix() {
		return getModuleName().toLowerCase(Locale.US);
	}

	/**
	 * 获取识别注解。识别@Entity和@MappedSuperclass。一个用于实体类、一个用于实体类的父类
	 * @return
	 */
	@Override
	protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
		return Arrays.asList(Entity.class, MappedSuperclass.class);
	}

	/**
	 * 获取识别类型,识别JpaRepository接口类。父类RepositoryConfigurationExtensionSupport.isStrictRepositoryCandidate()方法调用
	 * @return
	 */
	@Override
	protected Collection<Class<?>> getIdentifyingTypes() {
		return Collections.<Class<?>> singleton(JpaRepository.class);
	}

    // 省略其他

}

在上面的2.2.2最后的元数据判断时,如果传入的strictMatchesOnly为true,会调用JpaRepositoryConfigExtension.getIdentifyingTypes()方法,判断Repository<T, ID>接口中的T是否添加了@Entity或@MappedSuperclass注解。

此处的getRepositoryFactoryBeanClassName()方法返回JpaRepositoryFactoryBean类名。

Repository加入Spring IOC容器

Spring启动时,通过ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars() -> ImportBeanDefinitionRegistrar.registerBeanDefinitions() -> AbstractRepositoryConfigurationSourceSupport.registerBeanDefinitions() -> RepositoryConfigurationDelegate.registerRepositoriesIn(),一步一步调用,执行到RepositoryConfigurationDelegate的registerRepositoriesIn()方法,代码如下:

public class RepositoryConfigurationDelegate {
	public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry,
			RepositoryConfigurationExtension extension) {

		if (logger.isInfoEnabled()) {
			logger.info(LogMessage.format("Bootstrapping Spring Data %s repositories in %s mode.", //
					extension.getModuleName(), configurationSource.getBootstrapMode().name()));
		}

		extension.registerBeansForRoot(registry, configurationSource);

		RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension,
				configurationSource, resourceLoader, environment);

		if (logger.isDebugEnabled()) {
			logger.debug(LogMessage.format("Scanning for %s repositories in packages %s.", //
					extension.getModuleName(), //
					configurationSource.getBasePackages().stream().collect(Collectors.joining(", "))));
		}

		StopWatch watch = new StopWatch();
		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(", ")));
		watch.start();

		// 获取所有的Repository类,如GoodsRepository
		Collection<RepositoryConfiguration<RepositoryConfigurationSource>> configurations = extension
				.getRepositoryConfigurations(configurationSource, resourceLoader, inMultiStoreMode);

		List<BeanComponentDefinition> definitions = new ArrayList<>();

		Map<String, RepositoryConfiguration<?>> configurationsByRepositoryName = new HashMap<>(configurations.size());
		Map<String, RepositoryConfigurationAdapter<?>> metadataByRepositoryBeanName = new HashMap<>(configurations.size());

		for (RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration : configurations) {
			// key为Repository类的接口名称,如com.jingai.jpa.dao.entity.GoodsRepository.class
			configurationsByRepositoryName.put(configuration.getRepositoryInterface(), configuration);
			// 创建一个BeanDefinitionBuilder
			BeanDefinitionBuilder definitionBuilder = builder.build(configuration);
			// definitionBuilder中添加transactionManager、entityManager等属性信息
			extension.postProcess(definitionBuilder, configurationSource);

			if (isXml) {
				extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource) configurationSource);
			} else {
				// definitionBuilder中添加enableDefaultTransactions属性信息
				extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
			}

			// 从builder中获取beanDefinition
			RootBeanDefinition beanDefinition = (RootBeanDefinition) definitionBuilder.getBeanDefinition();
			beanDefinition.setTargetType(getRepositoryFactoryBeanType(configuration));
			beanDefinition.setResourceDescription(configuration.getResourceDescription());

			// 获取bean的名称,如goodsRepository
			String beanName = configurationSource.generateBeanName(beanDefinition);

			if (logger.isTraceEnabled()) {
				logger.trace(LogMessage.format(REPOSITORY_REGISTRATION, extension.getModuleName(), beanName,
						configuration.getRepositoryInterface(), configuration.getRepositoryFactoryBeanClassName()));
			}
			// 保存
			metadataByRepositoryBeanName.put(beanName, builder.buildMetadata(configuration));
			// 自动注册goodsRepository,添加到bean容器
			registry.registerBeanDefinition(beanName, beanDefinition);
			definitions.add(new BeanComponentDefinition(beanDefinition, beanName));
		}

		potentiallyLazifyRepositories(configurationsByRepositoryName, registry, configurationSource.getBootstrapMode());

		watch.stop();
		repoScan.tag("repository.count", Integer.toString(configurations.size()));
		repoScan.end();

		if (logger.isInfoEnabled()) {
			logger.info(
					LogMessage.format("Finished Spring Data repository scanning in %s ms. Found %s %s repository interface%s.",
							watch.lastTaskInfo().getTimeMillis(), configurations.size(), extension.getModuleName(),
							configurations.size() == 1 ? "" : "s"));
		}

		registerAotComponents(registry, extension, metadataByRepositoryBeanName);

		return definitions;
	}
}

3.1 通过RepositoryConfigurationExtension.getRepositoryConfigurations()方法,也就是前面讲解的RepositoryConfigurationExtensionSupport的getRepositoryConfigurations()方法,获取所有实现Repository接口的类,封装成RepositoryConfiguration;

3.2 遍历RepositoryConfiguration,调用builder.build()方法,创建一个BeanDefinitionBuilder对象;其中build()方法如下:

class RepositoryBeanDefinitionBuilder {

	public BeanDefinitionBuilder build(RepositoryConfiguration<?> configuration) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(resourceLoader, "ResourceLoader must not be null");

		// configuration.getRepositoryFactoryBeanClassName()返回org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean
		// 创建一个BeanDefinitionBuilder对象,其factoryMethodName为null
		// BeanDefinitionBuilder.rootBeanDefinition()方法会将"org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean"
		// 赋值给BeanDefinition的beanClass
		BeanDefinitionBuilder builder = BeanDefinitionBuilder
				.rootBeanDefinition(configuration.getRepositoryFactoryBeanClassName());

		builder.getRawBeanDefinition().setSource(configuration.getSource());
		// 构造方法参数值为接口名,如com.jingai.jpa.dao.GoodsRepository
		builder.addConstructorArgValue(configuration.getRepositoryInterface());
		// 配置属性。在RepositoryComponentProvider的findCandidateComponents()方法中,调用
		// AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate)
		// 解析类的@Lazy、@Primary、@DependOn、@Role、@Description等注解得到的值
		builder.addPropertyValue("queryLookupStrategyKey", configuration.getQueryLookupStrategyKey());
		builder.addPropertyValue("lazyInit", configuration.isLazyInit());
		builder.setLazyInit(configuration.isLazyInit());
		builder.setPrimary(configuration.isPrimary());

		configuration.getRepositoryBaseClassName()//
				.ifPresent(it -> builder.addPropertyValue("repositoryBaseClass", it));
		// extension.getDefaultNamedQueryLocation()返回classpath*:META-INF/jpa-named-queries.properties
		NamedQueriesBeanDefinitionBuilder definitionBuilder = new NamedQueriesBeanDefinitionBuilder(
				extension.getDefaultNamedQueryLocation());
		configuration.getNamedQueriesLocation().ifPresent(definitionBuilder::setLocations);

		String namedQueriesBeanName = BeanDefinitionReaderUtils
				.uniqueBeanName(extension.getModuleIdentifier() + ".named-queries", registry);
		BeanDefinition namedQueries = definitionBuilder.build(configuration.getSource());
		registry.registerBeanDefinition(namedQueriesBeanName, namedQueries);

		builder.addPropertyValue("namedQueries", new RuntimeBeanReference(namedQueriesBeanName));

		registerCustomImplementation(configuration).ifPresent(it -> {
			builder.addPropertyReference("customImplementation", it);
			builder.addDependsOn(it);
		});

		String fragmentsBeanName = registerRepositoryFragments(configuration);
		builder.addPropertyValue("repositoryFragments", new RuntimeBeanReference(fragmentsBeanName));

		return builder;
	}
}

核心逻辑是执行configuration.getRepositoryFactoryBeanClassName()返回org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean,创建一个BeanDefinitionBuilder对象,其factoryMethodName为null
BeanDefinitionBuilder.rootBeanDefinition()方法会将"org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean"赋值给BeanDefinition的beanClass。

3.3 获取builder中的BeanDefinition对象,执行registry.registerBeanDefinition(beanName, beanDefinition),将Repository类及对应的beanDefinition添加到Spring IOC容器中;

小结

本篇源码比较多,做一个简单总结:

1、在SpringBoot中引入spring-boot-starter-data-jpa依赖时,会自动注入JpaRepositoriesAutoConfiguration,从而注入JpaRepositoryConfigExtension;

2、在JpaRepositoryConfigExtension的父类RepositoryConfigurationExtensionSupport的getRepositoryConfigurations()方法,获取所有实现Repository接口的类,封装成RepositoryConfiguration;

3、SpringBoot启动时,会执行RepositoryConfigurationDelegate的registerRepositoriesIn()方法,在该方法中,调用2中的方法,获取所有实现Repository接口的类,创建类的BeanDefinition对象,其中beanClass为"org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean"字符串。并执行registry.registerBeanDefinition(beanName, beanDefinition),将Repository类及对应的beanDefinition添加到Spring IOC容器中;

限于篇幅,本篇就先讲解到这里。

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

  • 21
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
很抱歉,由于篇幅限制,我无法在这里提供整个项目的完整源代码。但我可以为您提供一些示例代码来演示如何实现根据不同的登录方式使用不同的数据库操作方式。 首先,您可以创建一个包含用户信息的数据库表,并在应用程序中创建对应的Java实体类。例如,以下代码显示了一个名为User的实体类: ```java @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String email; private String phone; private String password; // getters and setters } ``` 接下来,您可以为每种数据库操作方式创建相应的DAO接口。例如,以下代码显示了一个名为UserJdbcDao的JDBC DAO接口: ```java public interface UserJdbcDao { User findByUsernameAndPassword(String username, String password); } ``` 然后,您可以实现这些DAO接口。例如,以下代码显示了一个名为UserJdbcDaoImpl的JDBC DAO实现类: ```java @Repository public class UserJdbcDaoImpl implements UserJdbcDao { private final JdbcTemplate jdbcTemplate; @Autowired public UserJdbcDaoImpl(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public User findByUsernameAndPassword(String username, String password) { String sql = "SELECT * FROM users WHERE username = ? AND password = ?"; return jdbcTemplate.queryForObject(sql, new Object[]{username, password}, new UserRowMapper()); } private static class UserRowMapper implements RowMapper<User> { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(rs.getLong("id")); user.setUsername(rs.getString("username")); user.setEmail(rs.getString("email")); user.setPhone(rs.getString("phone")); user.setPassword(rs.getString("password")); return user; } } } ``` 类似地,您可以创建相应的MyBatis DAO接口和Spring Data JPA DAO接口,并实现它们。 最后,您可以创建一个处理登录请求的控制器,并在其中根据用户输入的登录信息选择使用哪种DAO。例如,以下代码显示了一个名为LoginController的登录控制器: ```java @RestController @RequestMapping("/login") public class LoginController { private final UserJdbcDao userJdbcDao; private final UserMyBatisDao userMyBatisDao; private final UserRepository userRepository; @Autowired public LoginController(UserJdbcDao userJdbcDao, UserMyBatisDao userMyBatisDao, UserRepository userRepository) { this.userJdbcDao = userJdbcDao; this.userMyBatisDao = userMyBatisDao; this.userRepository = userRepository; } @PostMapping public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) { User user; if (isEmail(loginRequest.getUsername())) { user = userMyBatisDao.findByEmailAndPassword(loginRequest.getUsername(), loginRequest.getPassword()); } else if (isPhone(loginRequest.getUsername())) { user = userRepository.findByPhoneAndPassword(loginRequest.getUsername(), loginRequest.getPassword()); } else { user = userJdbcDao.findByUsernameAndPassword(loginRequest.getUsername(), loginRequest.getPassword()); } if (user == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } else { return ResponseEntity.ok(user); } } private boolean isEmail(String str) { // check if str is a valid email } private boolean isPhone(String str) { // check if str is a valid phone number } } ``` 在上面的代码中,LoginController使用了@Autowired注解注入了UserJdbcDao、UserMyBatisDao和UserRepository。然后,它使用isEmail()和isPhone()方法来判断用户输入的登录信息是用户名、邮箱还是手机号,并根据不同的情况选择使用不同的DAO。 当然,这只是一个简单的示例,您需要根据您的具体需求进行修改和完善。但是,希望这可以为您提供一些帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值