The underlying source solutions for multiple BeanDefinitionScanner in spring

huisheng_qaq 2022-09-23 08:36:25 阅读数:806

underlyingsourcesolutionsmultiplebeandefinitionscanner

springSource series of whole section

Only talk about the source code,只玩真实.And the interviewer seriously have the source code


【一】springSuper explanation source setup

【二】springSource core principle underlying movement of super explanation

【三】spring源码之ApplicationContext超级详解

【四】spring源码之BeanDefinitionScan超级详解

【五】spring源码之BeanDefinitionRead超级详解

【六】spring源码之IOCThe loading process of super explanation andBean的生命周期

【七】spring源码之AOPThe loading process and the underlying principle

【八】spring源码之AOP的使用详解

【九】springSource of circular dependencies super explanation

【十】springSource of custom annotations super explanation

【十一】springSource of the transaction underlying super explanation

【十二】springThe underlying source of events super explanation


一,BeanDefinitionScanner加载流程

1,Source code analysis preparation

Based on the analysis of the source code,First you need to go to the website to download thisspring的源码包,建议下载5.x.x的版本

我这里安装的是:https://github.com/spring-projects/spring-framework/tree/5.2.9

2,源码分析

1,ApplicationContextIs involved in the wholespringIoc的加载流程,因此ApplicationContext也是作为SpringIocOne of the entrance.由于ApplicationContext接口有很多的实现类,So here use annotations to obtain the content of the context.

Through this annotation class firstAnnotationConfigApplicationContextGet all the information in this context,Then loading the configuration information inside,环境等.

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);

2,然后进入这个AnnotationConfigApplicationContext类里面,Can be found that there is a no arguments constructor,Register configuration class methods and arefresh刷新IOC容器的方法,Here mainly to see the no arguments constructor.

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {

//调用构造函数
this();
//注册我们的配置类
register(annotatedClasses);
//IOC容器刷新接口
refresh();
}

3,在这个构造函数里面,会实例化一个BeanDefinitionReaderA reader and aBeanDefinitionScanner的扫描器.The reader is to read the note,The scanner to scan the package and class,The final registration as aBeanDefinition,这个DefinitionScanner Also is the core content of this article

public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {

super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

4,在这个ClassPathBeanDefinitionScanner类的构造方法里面,Will first review the current environmental and resource loaders,There is another important thing is to have a initialize a default filter method.

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {

this.registry = registry;
if (useDefaultFilters) {

registerDefaultFilters();
}
//设置环境对象
setEnvironment(environment);
//设置资源加载器
setResourceLoader(resourceLoader);
}

Then you can come look at thisregisterDefaultFilters的方法,It will initialize theincludeFilterThis includes filters,其底层就是一个List集合.The contained filters will be added to all the [email protected]注解的类,并且在spring中,这个@ComponentThis annotation is scanned at this stage.This will include filters is to become a candidate in the behind ofbean的时候起到作用.

private final List<TypeFilter> includeFilters = new LinkedList<>();
protected void registerDefaultFilters() {

//加入扫描我们的@Component的
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
}

5,接下来进入这个ClassPathBeanDefinitionScannerScan class,会有一个scan方法,And then begin the real path to the package scanning.

public int scan(String... basePackages) {

//对这些pachageThese packages were scanned
doScan(basePackages);
}

接下来进入这个doScan的这个方法里面,Just start scanning bag.

protected Set < BeanDefinitionHolder > doScan(String...basePackages) {

//创建bean定义的holder对象用于保存扫描后生成的bean定义对象
Set <BeanDefinitionHolder> beanDefinitions = new LinkedHashSet <> ();
//循环我们的包路径集合
for (String basePackage: basePackages) {

//找到候选的Components
Set < BeanDefinition > candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate: candidates) {

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//设置我们的beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//这是默认配置 autowire-candidate
if (candidate instanceof AbstractBeanDefinition) {

postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
//获取@Lazy @DependsOn等注解的数据设置到BeanDefinition中
if (candidate instanceof AnnotatedBeanDefinition) {

AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//把我们解析出来的组件bean定义注册到我们的IOC容器中(容器中没有才注册)
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;
}

6,在上面的doScan方法里面,会有一个**findCandidateComponents(basePackage)**的方法,Mainly in order to find the need to generatebeanDefinition的候选者.进入这个方法,There's a thescanCandidateComponentsMethod is used to scan all the candidates.并且里面有一个componentsIndex的一个索引,Mainly in order to increase the efficiency of the query

public Set < BeanDefinition > findCandidateComponents(String basePackage) {

if (this.componentsIndex != null && indexSupportsIncludeFilters()) {

return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
} else {

return scanCandidateComponents(basePackage);
}
}

7,When looking at the nextscanCandidateComponents方法,Is used to scan the candidateComponent配置类的.这里面的basePackageIs the specific package path,比如说com.zhs.study,The final path will this package into resource pathcom/zhs/study.Then go to traverse the resource collection,Finally figure out whether these packages path the following class a candidatecomponent

private Set <BeanDefinition> scanCandidateComponents(String basePackage) {

Set <BeanDefinition> candidates = new LinkedHashSet<>();
try {

//把我们的包路径转为资源路径 com/zhs/study
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//扫描指定包路径下面的所有.class文件
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
//遍历这个resources集合
for (Resource resource : resources) {

try {

//Get the current class of a reader,You can read the current class name of the class,注解等
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//Whether the current class is a candidatebean
if (isCandidateComponent(metadataReader)) {

//If this class is an effectivebean
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
//Judge attributes of a class,Such as whether the interface,抽象类,内部类等,If it is also not registered
if (isCandidateComponent(sbd)) {

//加入到集合中
candidates.add(sbd);
}
}
}
}
}
}

8,Whether this class is an effectivebean的方法如下,Mainly in the isCandidateComponent 方法里面实现.

  • First will decide whether the class is in thisexcludeFiltersExclude filters inside,如果在里面,那么直接返回false;

  • If not exclude filters inside,So will determine in thisincludeFiltersContained filter,Is to evaluate the class above have [email protected]的这个注解.

  • 如果有这个@Component注解,And to judge this class if [email protected]这个条件注解,如果有这个注解,Will determine whether can meet the requirements of inside,如果符合条件,You can be aBeanDefinition;如果没有这个注解,You can through the filter,可以成为一个BeanDefinition

  • If all is not in the two filters,So also returns afalse,表示不符合条件

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {

//通过excludeFilters Whether to need to rule out
for (TypeFilter tf: this.excludeFilters) {

if (tf.match(metadataReader, getMetadataReaderFactory())) {

return false;
}
}
//includeFilters Do you need to include
for (TypeFilter tf: this.includeFilters) {

if (tf.match(metadataReader, getMetadataReaderFactory())) {

return isConditionMatch(metadataReader);
}
}
return false;
}
//如果有这个@Component的这个注解,Can judge this again again this class if add [email protected]的这个注解
private boolean isConditionMatch(MetadataReader metadataReader) {

if (this.conditionEvaluator == null) {

this.conditionEvaluator =
new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
}
return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}

9,If this class is an effectivebean,So and embedded inside a isCandidateComponent The method of Boolean type,Mainly to determine the effectivebeanWhat kind of class is a class.If it is not some interface,抽象类,内部类等,So will the effectiveBeanDefinition对象加入setSet to return to.

protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {

AnnotationMetadata metadata = beanDefinition.getMetadata();
// metadata.isIndependent()=顶级类、嵌套类、静态内部类
// metadata.isConcrete() =非接口、非抽象类
// metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName() = Abstract classes and methods is a [email protected]
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}

10,回到5里面的doScan方法,To get the all of the need to generateBeanDefinition之后,She will go to theBeanDefinitionFor an initial value assignment.For example set some scope,bean的名字,是否懒加载等.

String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//这是默认配置 autowire-candidate
if (candidate instanceof AbstractBeanDefinition) {

postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
//获取@Lazy @DependsOn等注解的数据设置到BeanDefinition中
if (candidate instanceof AnnotatedBeanDefinition) {

AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}

11,Still is to go back to5里面的doScan的方法里面,Set up after some of the properties,Will start to thisBeanDefinition注册到这个springIocThe container.First of all make thisBeanDefinitionIn the container if there is a,如果不存在,那么就会将这个BeanDefinition注册到这个springIoc的容器里面.

//把我们解析出来的组件bean定义注册到我们的IOC容器中(容器中没有才注册)
if (checkCandidate(beanName, candidate)) {

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}

二,总结

1,BeanDifinitionScanner执行流程总结

在这里插入图片描述

  • 1,首先会调用一个scan的一个方法,然后调用里面的doscanMethods to start real scan.

  • 2,First of all scans all package path,Get a package all the classes below,Then these classes will be a candidate for class,If meet the conditions can be eventuallyBeanDefinition.

  • 3,The rules of the candidate as follows,First will decide whether the class is in aexcludeFiltersExclude filters inside,如果在里面,那么直接返回;To assess the this class is in aincludeFiltersThe contained filter,Is this class if [email protected]这个类的注解,没有则直接return返回;Any continued to assess the this class if [email protected]的条件注解,If any have a look at whether the class should meet in conditional expression,If you don't meet directlyreturn返回,If meet can be an effectiveBeanDifinition,If the top of the class without [email protected]的这个注解,So will also be an effectiveBeanDifinition

  • 4,In be an effectiveBeanDefinition之后,Make thisBeanDefinitionWhat class is a type of,如果是接口,抽象类,内部类等,那么直接return ;如果不是接口,抽象类,内部类等,So will the effective class to join to thisset集合里面,最后返回这个set集合

  • 5,在获取到所有的BeanDefinition之后,会设置一些BeanDefinition的一些属性,As some scope、是否懒加载等,并且这些BeanDefinition都会加入到一个BeanDefinitionMap里面

  • 6,Eventually to judge thisIocContainer whether there is thisBeanDefinition,如果不存在,So will pass thisbeanDefinitionRegistry将这个BeanDefinition注册到Spring的Ioc容器里面

2,@Component注解总结

就是在spring启动时,这个加了@ComponentThis annotation above the class,是在这个@IncludeFilterContained filter is created and loaded.在创建这个@IncludeFilter的时候,Will go to get all the added [email protected]这个注解的类,Will take these classes loaded into thisSpring的容器里面.

copyright:author[huisheng_qaq],Please bring the original link to reprint, thank you. https://en.javamana.com/2022/266/202209230821200338.html