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的自动注入(一)
前言
前面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。
结合上面调用构造函数时创建的过滤器可知:
默认的ClassPathScanningCandidateComponentProvider,
includeFilters包含添加了@Component、@Repository、@Service、@Controller注解的类【@Repository、@Service、@Controller注解添加了@Component,也会扫描】,会扫描。excludeFilters为空。该默认方式也是Spring默认处理的方式,所以在类中添加上面的注解,即可自动注入到Spring IOC容器;
对于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容器中;
限于篇幅,本篇就先讲解到这里。
关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。