1.spring启动的时候会调用ClassPathBeanDefinitionScanner这个类里面的doScan()方法去扫描包下的路径
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
2.这个方法主要就是进行扫描忘记路径,然后得到一个beanDefinition集合
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
//遍历扫描路径
for (String basePackage : basePackages) {
//扫描得到beanDefinition,主要进行行excludeFilters、includeFilters判断和Conditional判断
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//遍历BeanDefinition
for (BeanDefinition candidate : candidates) {
//解析scope注解信息
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//设置scope注解信息
candidate.setScope(scopeMetadata.getScopeName());
主要是解析Component有没有设置bean的名字,有则直接返回,
// 没有则根据短名构造一个(如果写的名字第1、2个字符是大写则直接返回,否则直接将第一个字符转成小写返回)
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//主要是给BeanDefinition设置一些默认的值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description注解,为这些注解设置值
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查Spring容器中是否已经存在该beanName,有的话会判断是否匹配,匹配则不会加入spring容器
//不匹配则抛出异常,没有则直接加入spring容器
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;
}
3.这里面首先是构造一个集合beanDefinition,然后遍历传进来的扫描路径,通过findCandidateComponents这个方法处理扫描路径,我们来看看这个方法主要是干什么的:
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
//解析是否有文件写的有component注解
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
if()里面就是判断META-INF目录下面是否有写components文件(在该文件里面可以直接定义bean)然后在解析这个文件,其逻辑大致和下面一样。 通过scanCandidateComponents这个方法返回BeanDefinition集合。该方法主要是获得扫描路径下面的所有file对象,然后读取注解信息,判断与excludeFilters、includeFilters是否匹配以及Conditional判断,最后判断是否为接口、抽象类、独立类、以及lookup注解,最终返回BeanDefinition
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 获取basePackage下所有的文件资源
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//classpath文件下的所有file对象
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 {
//resource:AppConfig.class
//元数据读取器,读取注解的信息,类的信息,接口抽象类,父类等
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
/*读取类的信息进行判断excludeFilters、includeFilters判断,以及Conditional判断,
是@Conditional注解则不是一个bean
*/
//判断是不是一个bean
if (isCandidateComponent(metadataReader)) { //@Component-->includeFilters
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
//把bean的属性设置进去,主要是名字
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);
}
}
}
}
getMetadataReader是元数据读取器,主要是读取注解的信息,类的信息,接口抽象类,父类等isCandidateComponent主要是判断是否与excludeFilters、includeFilters匹配,spring启动的时候会为includeFilters设置一个默认值也就是@Component
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
//和排除过滤器匹配,不是一个bean
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional
for (TypeFilter tf : this.includeFilters) {
//只要有一个就匹配
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
isCandidateComponent该方法执行完之后如果为true表示是一个bean则会进入if逻辑里面,首先的话主要是设置bean的部分属性,然后调用isCandidateComponent(sbd)方法判断是否是接口抽象类...注意这两个isCandidateComponent穿的参数不一样执行逻辑也不一样
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
//不是独立的类不能成为bean,接口或者抽象类不能成为bean,但抽象类若有Lookup注解则可以成为bean
//Lookup注解:比如UserService里面依赖注入了一个user,该user是prototype,UserService里面有一个test方法输出user
//最终打印出来的是同一个,因为UserService是单例的,此时user加了Lookup注解的话就能达到我们预期的效果
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
若返回是true时就直接将其加入BeanDefinition集合里面返回candidates.add(sbd);
最终findCandidateComponents方法就是返回一个BeanDefinition集合,然后接下来就是遍历这个集合,对集合中的BeanDefinition进行处理,比如设置scope注解信息,beanName,解析@Lazy、@Primary、@DependsOn、@Role、@Description注解
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//遍历BeanDefinition
for (BeanDefinition candidate : candidates) {
//解析scope注解信息
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//设置scope注解信息
candidate.setScope(scopeMetadata.getScopeName());
主要是解析Component有没有设置bean的名字,有则直接返回,
// 没有则根据短名构造一个(如果写的名字第1、2个字符是大写则直接返回,否则直接将第一个字符转成小写返回)
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//主要是给BeanDefinition设置一些默认的值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description注解,为这些注解设置值
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
generateBeanName实则就是设置bean的名字,其逻辑大致是:解析Component有没有设置bean的名字,有则直接返回, 没有则根据短名构造一个(如果写的名字第1、2个字符是大写则直接返回,否则直接将第一个字符转成小写返回)
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
// 获取注解所指定的beanName
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
//有指定的则直接返回
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
//没有指定的则根据类的短名生成默认的名字
return buildDefaultBeanName(definition, registry);
}
设置完bean的名字之后就是调用postProcessBeanDefinition方法给bean赋一些默认值,然后调用processCommonDefinitionAnnotations解析处理一些注解
if (candidate instanceof AbstractBeanDefinition) {
//主要是给BeanDefinition设置一些默认的值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description注解,为这些注解设置值
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
最后就是检查Spring容器中是否已经存在该beanName,有的话会先判断是否兼容,就是对于的路径resource是不是一样的,匹配则不会加入spring容器不匹配则抛出异常,没有则直接加入spring容器
// 检查Spring容器中是否已经存在该beanName,有的话会判断是否兼容,兼容则不会加入spring容器
//不兼容则抛出异常,没有则直接加入spring容器
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册
registerBeanDefinition(definitionHolder, this.registry);
}
通过checkCandidate方法判断
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
//容器里面没有该BeanDefinition
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
//检查是否以及有该BeanDefinition
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
// 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}