SpringDataJPA+Hibernate框架源码剖析系列文章:
- SpringDataJPA+Hibernate框架源码剖析(一)框架介绍
- SpringDataJPA+Hibernate框架源码剖析(二)框架整合 之 EntityManagerFactory的构建
- SpringDataJPA+Hibernate框架源码剖析(三)框架整合 之 Repository接口实现的生成
- SpringDataJPA+Hibernate框架源码剖析(四)框架整合 之 事务管理器的构建(包括spring的事务机制)
- SpringDataJPA+Hibernate框架源码剖析(五)框架整合 之 SpringBoot整合JPA剖析
- SpringDataJPA+Hibernate框架源码剖析(六)@PersistenceContext和@Autowired注入EntityManager的区别
SpringDataJPA+Hibernate框架整合主要关注三个方面:EntityManagerFactory的构建、Repository接口实现的生成、事务管理器的构建。
注:spring是采用注解式配置;为了控制篇幅本系列主要分析JPA和hibernate相关源码,需要配置过程和pom依赖的同学请自行百度。
文章目录
- Repository接口实现的生成
- 一、手写实现@EnableJpaRepositories注解功能
- 二、 @EnableJpaRepositories注解源码剖析
- 1、@EnableJpaRepositories注解在何处被解析
- 2、源码如何解决上述两个问题的
- 2.1、 首先自定义一个ClassPathScanningCandidateComponentProvider重写isCandidateComponent方法,调用其findCandidateComponents()方法扫描Repository相关包获取其BeanDefinition(className=Repository接口的类型类)封装成RepositoryConfiguration对象。
- 2.2、 创建ClassName=JpaRepositoryFactoryBean的BeanDefinition,并设置构造函数参数为当前Repository的类型类,用于FactoryBean的getObjectType()方法返回
- 2.3、 第三步很简单将封装了ClassName=JpaRepositoryFactoryBean的BeanDefinition注册到BeanDefinitionRegistry中
- 3、JpaRepositoryFactoryBean如何获取代理Repository分析
Repository接口实现的生成
在我们在开发中大多是面向Repository接口编程,Repository 接口是 Spring Data JPA 中为我们提供的所有接口中的顶层接口,而且是个标志接口,Repository 提供了两种查询方式的支持
1) 基于方法名称命名规则查询
2)基于@Query 注解查询
开启Repository的配置只是一个注解@EnableJpaRepositories(value =“repository的包路径”)
接下来主要探讨下这个注解干了什么,Repository接口的实现是如何生成并注册到spring容器中的。
一、手写实现@EnableJpaRepositories注解功能
1、@ComponentSacn扫描忽略接口问题分析
首先看下不加@EnableJpaRepositories正常执行代码会出现什么错误
public class RepositoryStart {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config.class);
UserRepository userRepository = context.getBean(UserRepository.class);
User user = userRepository.findById("yxf").get();
System.out.println(user);
BookRepository bookRepository = context.getBean(BookRepository.class);
Book book = bookRepository.findById("1").get();
System.out.println(book);
}
}
执行报错:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.jpademo.repository.UserRepository' available
注:首先科普一个spring初始化bean的知识:spring首先通过扫描XML的 标签、@Component系列注解、@Bean注解等将对应的bean解析成一个beanDefinition对象里面保存bean的class、bean是否懒加载、bean的初始化方法、bean的构造参数等全部信息,用于后续bean的创建及初始化。spring是先扫描完全部的bean信息全部生成beanDefinition,再遍历所有的beanDefinition一起进行初始化,并不是扫描一个初始化一个。
注:这块对spring源码不了解的同学可能看的有点懵,只能尽量讲的全面一些
结合上面报错我们可以发现在创建UserRepository时发现找不到对应的beanDefinition,也就是UserRepository没有被扫描到,首先UserRepository添加了@Component注解,@ComponentScan的扫描包路径也包含了UserRepository所在的包。那还是没有扫描到猜测应该是UserRepository在@ComponentScan进行包扫描是略过去了。那我们到@ComponentScan解析注解的源码找原因
总的入口是ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()方法,我们跳过其他环节直接看ConfigurationClassParser.doProcessConfigurationClass()方法
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
//解析@PropertySource注解
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 解析@ComponentScan注解
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// 对@ComponentScan注解执行扫描的核心步骤
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 解析@Import注解
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 解析@ImportResource注解
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 解析@Bean注解
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
然后调用ComponentScanAnnotationParser.parse()——>ClassPathBeanDefinitionScanner.doScan()
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
// 此处的basePackages为@ComponentScan中的value属性
for (String basePackage : basePackages) {
// 根据一定条件扫描basePackage包下的全部类,解析为BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
// 变量扫描到合格的BeanDefinition进行后置处理并且注册到BeanDefinitionRegistry中
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
当断点到findCandidateComponents()方法执行完毕后发现扫描了Repository所属的basePackage包路径但是并没有得到UserRepository和BookRepository的Beandefinition,所以进入ClassPathScanningCandidateComponentProvider.findCandidateComponents()——>ClassPathScanningCandidateComponentProvider.scanCandidateComponents()方法一探究竟
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 拼接包路径地址
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 获取包路径下的.class文件
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);
// 过滤1(是否继承Repository接口,是否有@Component系列注解等条件)
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
// 过滤2 (是否非接口非抽象类等条件)
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;
}
断点可知Repository是在过滤2被过滤掉的,进去一探究竟ClassPathScanningCandidateComponentProvider.isCandidateComponent()
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
// 这里的metadata.isConcrete() 其实就是 !(this.isInterface || this.isAbstract);即
// 不能是接口也不能是抽象类
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
分析到这里我们发现了问题就是@ComponentSacn扫描包的时候会忽略掉接口。
2、@ComponentSacn扫描忽略接口问题解决
试想如果我们自定义一个ClassPathScanningCandidateComponentProvider重写isCandidateComponent在上述扫描结束后再扫描一遍Repository相关包是不是就解决了,准备动手~
@Component
public class MyRepositoryBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
MyClassPathBeanDefinitionScanner myClassPathBeanDefinitionScanner=new MyClassPathBeanDefinitionScanner(registry);
// 过滤没有继承Repository的接口
myClassPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(Repository.class));
// 扫描Repository接口相关包生成beanDefinition并注册到BeanDefinitionRegistry
myClassPathBeanDefinitionScanner.scan("com.example.jpademo.repository");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("工厂初始化!!!");
}
public static class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner{
public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
super(registry);
}
/**
* 重写isCandidateComponent使得ClassPathBeanDefinitionScanner可以为接口创建beanDefinition
* @param beanDefinition
* @return
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface();
}
}
}
搞定!机智如我~这次再执行总可以了吧
执行报错:Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.jpademo.repository.BookRepository]: Specified class is an interface
吐了~他说BookRepository是个接口不能实例化,这里到了实例化这步也说明了BookRepository被扫描到了且将BeanDefinition注册到了容器,那是不是将解析后的BeanDefinition中的ClassName属性替换成BookRepository的实现类即可,重新修改下上面的代码,再重新下MyClassPathBeanDefinitionScanner的doSacn()方法
@Component
public class MyRepositoryBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
MyClassPathBeanDefinitionScanner myClassPathBeanDefinitionScanner=new MyClassPathBeanDefinitionScanner(registry);
// 过滤没有继承Repository的接口
myClassPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(Repository.class));
// 扫描Repository接口相关包生成beanDefinition并注册到BeanDefinitionRegistry
myClassPathBeanDefinitionScanner.scan("com.example.jpademo.repository");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("工厂初始化!!!");
}
public static class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner{
public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
super(registry);
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
// beanDefinitionHolders为扫描repository包获取到全部Repository接口的BeanDefinition
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
// 变量全部的BeanDefinition替换ClassName属性
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
Class entityClass=null;
try {
entityClass=Class.forName(beanDefinition.getBeanClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 如果这个BeanDefinition是BookRepository接口
if(BookRepository.class==entityClass){
beanDefinition.setBeanClassName("com.example.jpademo.repository.BookRepositoryImpl");
}
// 如果这个BeanDefinition是UserRepository接口
if(UserRepository.class==entityClass){
beanDefinition.setBeanClassName("com.example.jpademo.repository.UserRepositoryImpl");
}
}
return beanDefinitionHolders;
}
/**
* 重写isCandidateComponent使得ClassPathBeanDefinitionScanner可以为接口创建beanDefinition
* @param beanDefinition
* @return
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface();
}
}
}
如上代码,先不说执行结果如何,开发者每增加一个Repository都有增加一个RepositoryImpl实现类,都要在doSacn()方法中多加一个if,Spring肯定不会有这么呆的设计。而且这样的话还不如直接在RepositoryImpl实现类上加个@Component注解呢。
3、避免重复创建Repository实现问题解决
分析到这里又出现了新的问题,怎么避免重复创建Impl,避免doScan()中很多if的存在,所有的beanDefinition中的className都是同一个类。有经验的同学应该会想到Spring的FactoryBean机制和JDK的动态代理,废话不多说直接上代码
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
// beanDefinitionHolders为扫描repository包获取到全部Repository接口的BeanDefinition
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
Class entityClass = null;
try {
entityClass=Class.forName(beanDefinition.getBeanClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 为MyRepositoryFactoryBean的构造函数设置参数,动态传入每个Repository接口类型
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(entityClass);
// 将beanDefinition中的className属性替换成MyRepositoryFactoryBean
beanDefinition.setBeanClassName("com.example.jpademo.config.MyRepositoryFactoryBean");
}
return beanDefinitionHolders;
}
我们向beanDefinition中统一注入一个FactoryBean,看这个MyRepositoryFactoryBean类
public class MyRepositoryFactoryBean implements FactoryBean {
@PersistenceContext
private EntityManager entityManager;
// Repository接口类型
private Class<?> repositoryInterfaceClass;
public MyRepositoryFactoryBean(Class<?> repositoryInterfaceClass) {
this.repositoryInterfaceClass = repositoryInterfaceClass;
}
/**
* FactoryBean向容器中注入的bean
* @return
* @throws Exception
*/
@Override
public Object getObject() throws Exception {
// Repository都继承了JpaRepository<T, ID>,从JpaRepository中获取实体T的类型
ParameterizedType jpaRepositoryType = (ParameterizedType) repositoryInterfaceClass.getGenericInterfaces()[0];
Type entityType = jpaRepositoryType.getActualTypeArguments()[0];
// 获取实体T的全限定名
String entityClassName = entityType.getTypeName();
// 获取实体T的类型类
Class<?> entityClass = Class.forName(entityClassName);
// 根据JDK动态代理创建Repository的Impl实现类,InvocationHandler的实现类RepositoryProxy
return Proxy.newProxyInstance(MyRepositoryFactoryBean.class.getClassLoader(),new Class[]{repositoryInterfaceClass},new RepositoryProxy(entityManager,entityClass));
}
/**
* FactoryBean向容器中注入的bean类型
* @return
*/
@Override
public Class<?> getObjectType() {
return repositoryInterfaceClass;
}
}
向每个Repository接口中都注入一个MyRepositoryFactoryBean并设置构造参数为当前Repository的类型类,但是在后期spring初始化调用它的构造时传入的参数不同,所以MyRepositoryFactoryBean能向spring容器中注入对应的Repository实现类,其实现类就是getObject()方法的返回值。
所以每个Repository调用增删改查方法时都会调用RepositoryProxy.invoke方法,接下来我们只要在RepositoryProxy中实现一个通用的增删改查就大功告成了。
public class RepositoryProxy implements InvocationHandler {
// 自己创建的通用Repository,里面包含了简单的增删改查接口实现类JPaRepository接口的全部方法
private MySimpleRepository mySimpleRepository;
public RepositoryProxy(EntityManager entityManager, Class entityClass) {
this.mySimpleRepository = new MySimpleRepository(entityManager,entityClass);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("yxf自定义JPA执行"+method.getName()+"方法");
// 获取当前Repository被调用的方法
Method repositoryMethod = mySimpleRepository.getClass().getMethod(method.getName(), method.getParameterTypes());
// 调用MySimpleRepository中的对应方法实现
Object result = repositoryMethod.invoke(mySimpleRepository, args);
return result;
}
}
MySimpleRepository中提供了JapRepository的全部接口实现,这里就不全部手写了,具体就是使用EntityManager提供的API,最终实现还是Hibernate的Session提供的API。只简单实现下findById()方法用于测试
public class MySimpleRepository implements JpaRepository {
private EntityManager entityManager;
// 操作的实体类型
private Class<?> entityClass;
public MySimpleRepository(EntityManager entityManager, Class<?> entityClass) {
this.entityManager = entityManager;
this.entityClass = entityClass;
}
@Override
public Object save(Object entity) {
return null;
}
@Override
public Optional findById(Object o) {
return Optional.of(entityManager.find(entityClass,o));
}
...
}
大功告成~测试
执行结果:
yxf自定义JPA执行findById方法
20:46:09.769 [main] DEBUG org.hibernate.SQL - select user0_.id as id1_1_0_, user0_.age as age2_1_0_, user0_.name as name3_1_0_ from t_user user0_ where user0_.id=?
User{id='yxf', name='yangxiaofei', age=18}
yxf自定义JPA执行findById方法
20:46:09.910 [main] DEBUG org.hibernate.SQL - select book0_.bookId as bookid1_0_0_, book0_.bookName as bookname2_0_0_, book0_.userId as userid3_0_0_, user1_.id as id1_1_1_, user1_.age as age2_1_1_, user1_.name as name3_1_1_ from t_book book0_ left outer join t_user user1_ on book0_.userId=user1_.id where book0_.bookId=?
Book{bookId='1', bookName='水浒传'}
二、 @EnableJpaRepositories注解源码剖析
经过上面手写实现模块的分析,发现在不加@EnableJpaRepositories注解是一共存在两个问题
-
@ComponentSacn注解扫描会忽略接口,Repository接口无法被扫描解析成BeanDefinition
-
Repository接口就算被扫描到了,接口也没办法实例化,需要为每个Repository创建对应实现替换BeanDefinition的className属性
接下来看看官方是如何解决的
1、@EnableJpaRepositories注解在何处被解析
首先看下@EnableJpaRepositories的构成如下,Spring中@Enable相关的注解其作用大都是借助@Import来收集并注册特定场景相关的bean,这里的@EnableJpaRepositories主要是像容器中注入JPARepositoriesRegistrar。
接下来看下@EnableJpaRepositories在何处被解析,看到ConfigurationClassPostProcessor的核心方法processConfigBeanDefinitions()。(需要对spring源码有一点了解,不懂为什么从这里开始讲的可以直接搜ConfigurationClassPostProcessor,这说是spring中最重要的一个后置处理器也不为过)
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取registry中现有的BeanDefinition备用,后序会遍历分析他们,通过他们作为入口注入更多的BeanDefinition
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
// 在ConfigurationClassUtils.checkConfigurationClassCandidate()方法检测是否配置类候选者时会为配置类定性是full还是lite
// isFullConfigurationClass和isLiteConfigurationClass方法时检测beanDef是full还是lite,所以执行到这里的类都已经被处理过了
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 检查是否配置类的候选者,full模式和lite模式两种
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果不存在配置类直接return
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
// 创建配置类解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 需要解析的配置类
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 创建集合保存已经解析过的配置类
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 核心解析方法,解析当前Configuration配置类,扫描其@ComponentScan、@Import(@Eable系列注解里面都包含@Import)、@PropertySource
// @Bean、@ImportResource等注解。处理@ComponentScan注解扫描的类直接注册到BeanDefinitionRegistry之外,其余的注解都只做解析操作,解析完后
// 保存到当前Configuration配置类的BeanDefinition中,在下面的reader.loadBeanDefinitions()步骤中逐一使用向BeanDefinitionRegistry中注册
// 里面包含递归操作,对@ComponentScan注解扫描的类递归调用parse()方法进行解析,最终将当前Configuration配置类概括的全部Configuration合并。
parser.parse(candidates);
parser.validate();
// 解析配置类获得的子集配置类,这里的每个ConfigurationClass都对@ComponentScan、@Import(@Eable系列注解里面都包含@Import)、@PropertySource
// @Bean、@ImportResource等注解进行了解析
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 从中移除已经解析过的
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
// 创建配置类读取器
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 上面的parser.parse(candidates);只是统计当前Configuration配置类中的@Import、@Bean等数量,在此处进行注册
this.reader.loadBeanDefinitions(configClasses);
// 添加已经解析过的集合
alreadyParsed.addAll(configClasses);
// 下面就是几个集合将新旧配置类倒来倒去,重复上面的加载保证不会漏掉任何Configuration
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
上面关注两个关键地方
1.1、parser.parse(candidates);解析@Import注解将JPARepositoriesRegistrar封装到当前配置类的BeanDefinition的importBeanDefinitionRegistrars属性中
调用ConfigurationClassParser.parse()——>ConfigurationClassParser.processConfigurationClass()——>ConfigurationClassParser.doProcessConfigurationClass()
在这个方法里会对@PropertySource、@ComponentScan、@Import、@Bean等注解进行解析
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
//解析@PropertySource注解
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 解析@ComponentScan注解
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 解析@Import注解
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 解析@ImportResource注解
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 解析@Bean注解
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
这里我们关注@Import注解的解析processImports(configClass, sourceClass, getImports(sourceClass), true);
这里的第三个参数*getImports(sourceClass)*会查看这个配置类上是否有@Import注解,@EnableJpaRepositories中的@Import也会被获取到。
看processImports(configClass, sourceClass, getImports(sourceClass), true);方法,我们的@EnableJpaRepositories中注入的JPARepositoriesRegistrar属于第2种情况实现了ImportBeanDefinitionRegistrar接口,将其放入到当前配置类的importBeanDefinitionRegistrars属性中,用于后续的reader使用注入到BeanDefinitionRegistry
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
// @Import注解注入的这个类实现了ImportSelector接口
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
// 1. 是实现DeferredImportSelector延迟导入接口
// 进行延迟导入处理
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 调用ImportSelector的selectImports()方法获取全部导入的beanName
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
// 拿这些selectImports()得到的这些bean递归调用processImports方法
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
// 2. 实现了ImportBeanDefinitionRegistrar接口
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
// 将其放入到当前配置类的importBeanDefinitionRegistrars属性中,用于后续的reader使用注入到BeanDefinitionRegistry
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
// 3. 候选类不是ImportSelector 或 ImportBeanDefinitionRegistrar的实现,将其作为@Configuration类进行处理
// 添加到当前配置类的imports属性中用于后续的reader使用注入到BeanDefinitionRegistry
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 递归调用processConfigurationClass方法解析此bean
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
1.2 、this.reader.loadBeanDefinitions(configClasses); 如果当前配置类的BeanDefinition的importBeanDefinitionRegistrars属性不为空,遍历执行ImportBeanDefinitionRegistrar.registerBeanDefinitions()方法
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()——>ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass()
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
// 对当前Configuration上单纯的@Import导入类进行注册
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 对当前Configuration中的@Bean注解标注的方法进行注册
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 对当前Configuration上的@ImportedResources导入的类进行注册
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 对当前Configuration上@Import注入的ImportBeanDefinitionRegistrar遍历进行调用,调用其registerBeanDefinitions方法。
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
loadBeanDefinitionsFromRegistrars(),从当前configClass的ImportBeanDefinitionRegistrars属性中获取保存的ImportBeanDefinitionRegistrar调用registerBeanDefinitions方法,此处就包含JPARepositoriesRegistrar
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
// 遍历ImportBeanDefinitionRegistrar调用registerBeanDefinitions方法
registrar.registerBeanDefinitions(metadata, this.registry));
}
2、源码如何解决上述两个问题的
上面分析了@EnableJpaRepositories中注入的JPARepositoriesRegistrar.registerBeanDefinitions()方法何时被调用,接下来看下这个方法干了什么?是怎么解决上述两个问题的?与手写实现有何不同?
JPARepositoriesRegistrar.registerBeanDefinitions()——>RepositoryBeanDefinitionRegistrarSupport.registerBeanDefinitions()——>RepositoryConfigurationDelegate.registerRepositoriesIn()
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);
List<BeanComponentDefinition> definitions = new ArrayList<>();
StopWatch watch = new StopWatch();
if (logger.isDebugEnabled()) {
logger.debug(LogMessage.format("Scanning for %s repositories in packages %s.", //
extension.getModuleName(), //
configurationSource.getBasePackages().stream().collect(Collectors.joining(", "))));
}
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();
// 1.自定义一个ClassPathScanningCandidateComponentProvider重写isCandidateComponent方法,调用其findCandidateComponents()方法扫描Repository相关包获取其BeanDefinition(className=Repository接口的类型类)封装成RepositoryConfiguration对象。
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.创建ClassName=JpaRepositoryFactoryBean的BeanDefinition,并设置构造函数为
// 当前Repository的类型类,用于FactoryBean的getObjectType()方法返回
BeanDefinitionBuilder definitionBuilder = builder.build(configuration);
extension.postProcess(definitionBuilder, configurationSource);
if (isXml) {
extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource) configurationSource);
} else {
extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
}
AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
beanDefinition.setResourceDescription(configuration.getResourceDescription());
String beanName = configurationSource.generateBeanName(beanDefinition);
if (logger.isTraceEnabled()) {
logger.trace(LogMessage.format(REPOSITORY_REGISTRATION, extension.getModuleName(), beanName, configuration.getRepositoryInterface(),
configuration.getRepositoryFactoryBeanClassName()));
}
beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, configuration.getRepositoryInterface());
// 3. 将封装了ClassName=JpaRepositoryFactoryBean的BeanDefinition注册到BeanDefinitionRegistry中
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 interfaces.", //
watch.getLastTaskTimeMillis(), configurations.size(), extension.getModuleName()));
}
return definitions;
}
2.1、 首先自定义一个ClassPathScanningCandidateComponentProvider重写isCandidateComponent方法,调用其findCandidateComponents()方法扫描Repository相关包获取其BeanDefinition(className=Repository接口的类型类)封装成RepositoryConfiguration对象。
RepositoryConfigurationExtensionSupport.getRepositoryConfigurations()
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<>();
// 获取Repository包下的全部BeanDefinition,变量进行封装
for (BeanDefinition candidate : configSource.getCandidates(loader)) {
RepositoryConfiguration<T> configuration = getRepositoryConfiguration(candidate, configSource);
Class<?> repositoryInterface = loadRepositoryInterface(configuration,
getConfigurationInspectionClassLoader(loader));
if (repositoryInterface == null) {
result.add(configuration);
continue;
}
RepositoryMetadata metadata = AbstractRepositoryMetadata.getMetadata(repositoryInterface);
boolean qualifiedForImplementation = !strictMatchesOnly || configSource.usesExplicitFilters()
|| isStrictRepositoryCandidate(metadata);
if (qualifiedForImplementation && useRepositoryConfiguration(metadata)) {
result.add(configuration);
}
}
return result;
}
configSource.getCandidates(loader)——>RepositoryConfigurationSourceSupport.getCandidates()
@Override
public Streamable<BeanDefinition> getCandidates(ResourceLoader loader) {
// 自定义的ClassPathScanningCandidateComponentProvider子类,getIncludeFilters()包括Repository接口必须实现org.springframework.data.repository.Repository接口、Repository接口带有@RepositoryDefinition注解
RepositoryComponentProvider scanner = new RepositoryComponentProvider(getIncludeFilters(), registry);
scanner.setConsiderNestedRepositoryInterfaces(shouldConsiderNestedRepositories());
scanner.setEnvironment(environment);
scanner.setResourceLoader(loader);
getExcludeFilters().forEach(it -> scanner.addExcludeFilter(it));
// 调用其findCandidateComponents()方法扫描Repository相关包获取其BeanDefinition
return Streamable.of(() -> getBasePackages().stream()//
.flatMap(it -> scanner.findCandidateComponents(it).stream()));
}
******这里看下RepositoryComponentProvider重新后的isCandidateComponent方法
RepositoryComponentProvider.java
// 重新后的此方法如果beanDefinition的ClassName为接口也能返回true
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
boolean isNonRepositoryInterface = !ClassUtils.isGenericRepositoryInterface(beanDefinition.getBeanClassName());
boolean isTopLevelType = !beanDefinition.getMetadata().hasEnclosingClass();
boolean isConsiderNestedRepositories = isConsiderNestedRepositoryInterfaces();
return isNonRepositoryInterface && (isTopLevelType || isConsiderNestedRepositories);
}
到此源码针对**”@ComponentSacn扫描忽略接口”**问题分析完毕。
2.2、 创建ClassName=JpaRepositoryFactoryBean的BeanDefinition,并设置构造函数参数为当前Repository的类型类,用于FactoryBean的getObjectType()方法返回
builder.build(configuration);——》RepositoryBeanDefinitionBuilder.build()
public BeanDefinitionBuilder build(RepositoryConfiguration<?> configuration) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
Assert.notNull(resourceLoader, "ResourceLoader must not be null!");
// 创建一个新的BeanDefinition设置其BeanClassName=configuration.getRepositoryFactoryBeanClassName(),
// configuration.getRepositoryFactoryBeanClassName()获取的是@EnableJpaRepositories的repositoryFactoryBeanClass属性默认为JpaRepositoryFactoryBean。
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(configuration.getRepositoryFactoryBeanClassName());
builder.getRawBeanDefinition().setSource(configuration.getSource());
// 为BeanDefinition设置构造函数的入参为Repository的类型类
builder.addConstructorArgValue(configuration.getRepositoryInterface());
builder.addPropertyValue("queryLookupStrategyKey", configuration.getQueryLookupStrategyKey());
builder.addPropertyValue("lazyInit", configuration.isLazyInit());
builder.setLazyInit(configuration.isLazyInit());
builder.setPrimary(configuration.isPrimary());
// 忽略不关键步骤
...
return builder;
}
这里再看下
BeanDefinitionBuilder.rootBeanDefinition(configuration.getRepositoryFactoryBeanClassName());方法的调用链的关键赋值方法
BeanDefinitionBuilder.rootBeanDefinition()
public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName, @Nullable String factoryMethodName) {
BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new RootBeanDefinition());
// 设置BeanClassName=JpaRepositoryFactoryBean
builder.beanDefinition.setBeanClassName(beanClassName);
builder.beanDefinition.setFactoryMethodName(factoryMethodName);
return builder;
}
到此***”Repository接口就算被扫描到了,接口也没办法实例化,需要为每个Repository创建对应实现替换BeanDefinition的className属性“***问题解决
2.3、 第三步很简单将封装了ClassName=JpaRepositoryFactoryBean的BeanDefinition注册到BeanDefinitionRegistry中
3、JpaRepositoryFactoryBean如何获取代理Repository分析
根据上述分析可以发现Repository接口的实现类都是通过JpaRepositoryFactoryBean注入的,接下来就重点分析下JpaRepositoryFactoryBean创造Repository接口的实现类的过程
上图为JpaRepositoryFactoryBean的继承关系图,可以发现JpaRepositoryFactoryBean实现类InitializingBean接口,那我们首先看下其afterPropertiesSet()方法
public void afterPropertiesSet() {
// 1.创建RepositoryFactory
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);
// 2.调用factory.getRepository()方法获取Repository的实现类
this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));
// Make sure the aggregate root type is present in the MappingContext (e.g. for auditing)
this.mappingContext.ifPresent(it -> it.getPersistentEntity(repositoryMetadata.getDomainType()));
if (!lazyInit) {
this.repository.get();
}
}
这里我们关注两点:
3.1、 创建RepositoryFactory
首先看下createRepositoryFactory();看下这个RepositoryFactory到底是什么
TransactionalRepositoryFactoryBeanSupport.createRepositoryFactory()——>JpaRepositoryFactoryBean.doCreateRepositoryFactory()
protected RepositoryFactorySupport doCreateRepositoryFactory() {
Assert.state(entityManager != null, "EntityManager must not be null!");
// 这里传入了一个entityManager,下面看下entityManager哪里来的
return createRepositoryFactory(entityManager);
}
*********JpaRepositoryFactoryBean中的entityManager属性的set方法***********
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
// JpaRepositoryFactoryBean会被spring初始化会处理@PersistenceContext为其注入一个事务型的EntityManager
this.entityManager = entityManager;
}
JpaRepositoryFactoryBean.createRepositoryFactory()
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
// JpaRepositoryFactoryBean中的factory属性为JpaRepositoryFactory
JpaRepositoryFactory jpaRepositoryFactory = new JpaRepositoryFactory(entityManager);
jpaRepositoryFactory.setEntityPathResolver(entityPathResolver);
jpaRepositoryFactory.setEscapeCharacter(escapeCharacter);
if (queryMethodFactory != null) {
jpaRepositoryFactory.setQueryMethodFactory(queryMethodFactory);
}
return jpaRepositoryFactory;
}
3.2、 调用factory.getRepository()方法获取Repository的实现类
上面分析了RepositoryFactory的实现为JpaRepositoryFactory,接下来看下其getRepository()方法时如何创建Repository实现类的,首先看到factory.getRepository()调用的为其父类RepositoryFactorySupport.getRepository()
public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {
if (logger.isDebugEnabled()) {
logger.debug(LogMessage.format("Initializing repository instance for %s…", repositoryInterface.getName()));
}
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
Assert.notNull(fragments, "RepositoryFragments must not be null!");
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);
// 选择Repository的实现类,默认为SampleRepository
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);
// 获取Repository的实现类
Object target = getTargetRepository(information);
repositoryTargetStep.tag("target", target.getClass().getName());
repositoryTargetStep.end();
RepositoryComposition compositionToUse = composition.append(RepositoryFragment.implemented(target));
validate(information, compositionToUse);
// Create proxy
StartupStep repositoryProxyStep = onEvent(applicationStartup, "spring.data.repository.proxy", repositoryInterface);
// 创建代理工厂
ProxyFactory result = new ProxyFactory();
// 设置目标实现类
result.setTarget(target);
// 设置动态代理实现类要满足的接口
result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);
// 根据原Repository接口声明的方法添加不同的切面(标注TODO),比如:
// 1.是否声明基于方法名称命名规则查询
// 2.是否手动添加Impl进行方法实现
// 3.是否存在基于@Query 注解查询等
if (MethodInvocationValidator.supports(repositoryInterface)) {
// TODO
result.addAdvice(new MethodInvocationValidator());
}
// TODO
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)) {
// TODO
result.addAdvice(new DefaultMethodInvokingMethodInterceptor());
}
Optional<QueryLookupStrategy> queryLookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,
evaluationContextProvider);
// TODO
result.addAdvice(new QueryExecutorMethodInterceptor(information, getProjectionFactory(), queryLookupStrategy,
namedQueries, queryPostProcessors, methodInvocationListeners));
// TODO
result.addAdvice(
new ImplementationMethodExecutionInterceptor(information, compositionToUse, methodInvocationListeners));
// 创建被代理包装的Repository实现类
T repository = (T) result.getProxy(classLoader);
repositoryProxyStep.end();
repositoryInit.end();
if (logger.isDebugEnabled()) {
logger.debug(LogMessage.format("Finished creation of repository instance for {}.",
repositoryInterface.getName()));
}
return repository;
}
看下选择Repository的实现类,默认为SampleRepository的逻辑
RepositoryInformation information = getRepositoryInformation(metadata, composition);
RepositoryFactorySupport.getRepositoryInformation()
private RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata,
RepositoryComposition composition) {
RepositoryInformationCacheKey cacheKey = new RepositoryInformationCacheKey(metadata, composition);
return repositoryInformationCache.computeIfAbsent(cacheKey, key -> {
// 这里如果repositoryBaseClass 不是空的话去repositoryBaseClass
// 为空的话取getRepositoryBaseClass(metadata)
Class<?> baseClass = repositoryBaseClass.orElse(getRepositoryBaseClass(metadata));
return new DefaultRepositoryInformation(metadata, baseClass, composition);
});
}
JpaRepositoryFactory.getRepositoryBaseClass(metadata)
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleJpaRepository.class;
}
再看下创建被代理包装的Repository实现类
T repository = (T) result.getProxy(classLoader);
ProxyFactory.getProxy();到这里有没有发现很熟悉,这是SpringAOP代理对象创建流程
public Object getProxy(@Nullable ClassLoader classLoader) {
return this.createAopProxy().getProxy(classLoader);
}
有这里我们看JDK动态代理的实现
JdkDynamicAopProxy.getProxy()
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
到此JpaRepositoryFactoryBean如何获取代理Repository分析完毕,当Repository的代理实现类调用方法时进入JdkDynamicAopProxy.invoke()方法,在invoke()方法中获取刚刚为Repository设置的切面拦截器链,顺序执行。