ClassPathBeanDefinitionScanner包扫描解析Bean定义信息

546 阅读8分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

一、ClassPathBeanDefinitionScanner构造器

注意:@Service、@Repository、@Controller、@Configuration都是含有@Component注解

//bean名称生成器
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
//@Scope解析器
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

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

    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;

    if (useDefaultFilters) {
        registerDefaultFilters();
    }
    //设置环境信息
    setEnvironment(environment);
    //设置资源加载器
    setResourceLoader(resourceLoader);
}

1.1 设置资源加载器

public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
   //1.1.1创建资源解析器
   this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
   //创建元数据读取器工厂
   this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
   //加载META-INF/spring.components信息
   this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}

1.1.1 创建资源解析器

这里因为是AnnotationConfigServletWebServerApplicationContext容器继承了GenericApplicationContext

GenericApplicationContext实现了ResourcePatternResolver所以AnnotationConfigServletWebServerApplicationContext容器也是资源解析器

public static ResourcePatternResolver getResourcePatternResolver(@Nullable ResourceLoader resourceLoader) {
   if (resourceLoader instanceof ResourcePatternResolver) {
      return (ResourcePatternResolver) resourceLoader;
   }
   else if (resourceLoader != null) {
      return new PathMatchingResourcePatternResolver(resourceLoader);
   }
   else {
      return new PathMatchingResourcePatternResolver();
   }
}

1.2AnnotationBeanNameGenerator Bean名称生成器

生成Bean名称

public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
   //1.1.1 注解Bean
   if (definition instanceof AnnotatedBeanDefinition) {
      String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
      if (StringUtils.hasText(beanName)) {
         // Explicit bean name found.
         return beanName;
      }
   }
   //1.1.2 普通Bean
   return buildDefaultBeanName(definition, registry);
}

1.2.1 注解Bean

根据注解获取Bean名称

protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
   //获取注解元数据
   AnnotationMetadata amd = annotatedDef.getMetadata();
   //根据元数据获取Bean所有注解信息
   Set<String> types = amd.getAnnotationTypes();
   String beanName = null;
   for (String type : types) {
      //获取当前注解所有属性值
      AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
      if (attributes != null) {
         //从缓存中获取注解中所有注解元数据,如果没有从注解元数据中获取并放入缓存
         Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
            Set<String> result = amd.getMetaAnnotationTypes(key);
            return (result.isEmpty() ? Collections.emptySet() : result);
         });
         //判断条件 1.当前注解是否是@Component,@ManagedBean,@Named类型或者注解元数据有@Component类型  2.注解属性中含有value属性
         if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
            //从value属性中取值
            Object value = attributes.get("value");
            if (value instanceof String) {
               String strVal = (String) value;
               if (StringUtils.hasLength(strVal)) {
                  if (beanName != null && !strVal.equals(beanName)) {
                     throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
                           "component names: '" + beanName + "' versus '" + strVal + "'");
                  }
                  beanName = strVal;
               }
            }
         }
      }
   }
   return beanName;
}

判断条件

  • 1.当前注解是否是@Component,@ManagedBean,@Named类型或者注解元数据有@Component类型
  • 2.注解属性中含有value属性
protected boolean isStereotypeWithNameValue(String annotationType,
      Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes) {

   boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
         metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME) ||
         annotationType.equals("javax.annotation.ManagedBean") ||
         annotationType.equals("javax.inject.Named");

   return (isStereotype && attributes != null && attributes.containsKey("value"));
}

1.2.2 普通Bean

protected String buildDefaultBeanName(BeanDefinition definition) {
   //获取全限定类名例如:com.small.autoConfig.TestAutoConfig
   String beanClassName = definition.getBeanClassName();
   Assert.state(beanClassName != null, "No bean class name set");
   //去掉包路径获取bean名称TestAutoConfig
   String shortClassName = ClassUtils.getShortName(beanClassName);
   //将首字母转换成小写testAutoConfig
   return Introspector.decapitalize(shortClassName);
}

1.3 AnnotationScopeMetadataResolver @Scope注解解析器

1.3.1 @Scope注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
 
   //作用域范围 
   @AliasFor("scopeName")
   String value() default "";
 
   @AliasFor("value")
   String scopeName() default "";
 
   ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
 
}

1.3.1.1 作用域范围:value()和scopeName()

Spring中

  • singleton 饿汉加载(容器启动,Bean实例就创建好了,需要的时候从Spring容器中获取)
  • prototype 懒汉加载(IOC容器启动的时候,并不会创建对象实例,每次使用都会创建一个新对象)

Springmvc中

  • request 同一个请求创建一个实例
  • sessioon 同一个session创建一个实例
  • globalsession 同一个globalsession创建一个实例

1.3.1.2 作用域代理:proxyMode()

  • DEFAULT和NO 不使用作用域代理
  • INTERFACES 使用JDK动态代理模式
  • TARGET_CLASS 使用Cglib代理模式

1.3.2 解析@Scope

解析@Scope注解

public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
   ScopeMetadata metadata = new ScopeMetadata();
   //如果是注解Bean
   if (definition instanceof AnnotatedBeanDefinition) {
      AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
      //获取@Scope的属性值
      AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
            annDef.getMetadata(), this.scopeAnnotationType);
      if (attributes != null) {
         //获取@Scope的value属性值,并设置作用域
         metadata.setScopeName(attributes.getString("value"));
         //获取@Scope的proxyMode属性值
         ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
         //设置作用域代理
         if (proxyMode == ScopedProxyMode.DEFAULT) {
            proxyMode = this.defaultProxyMode;
         }
         metadata.setScopedProxyMode(proxyMode);
      }
   }
   return metadata;
}

二、doScan 扫描包

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) {
       //2.1扫描指定包,加载成BeanDefinition
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      for (BeanDefinition candidate : candidates) {
         //2.2解析作用域
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         //设置作用域
         candidate.setScope(scopeMetadata.getScopeName());
         //2.3设置Bean名称
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         //2.4 后置处理BeanDefinition
         if (candidate instanceof AbstractBeanDefinition) {
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         //2.5处理公共注解
         if (candidate instanceof AnnotatedBeanDefinition) {
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         //2.6检查BeanName是否冲突
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            //2.7注册BeanDefinition
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}

2.1findCandidateComponents 扫描指定包,加载成BeanDefinition

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    //如果META-INF下有spring.components则会走这逻辑(一般不用)
   if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   //2.1扫描指定包路径下的类
   else {
      return scanCandidateComponents(basePackage);
   }
}
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
   Set<BeanDefinition> candidates = new LinkedHashSet<>();
   try {
      // 2.1.1拼接包扫描路径 例如:classpath*:com/small/**/*.class
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
      //2.1.2 获取资源解析器并加载资源
      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 {
               //2.1.3将resource包装成SimpleMetadataReader并放入metadataReaderCache缓存中
               MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
               if (isCandidateComponent(metadataReader)) {
                  ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                  sbd.setSource(resource);
                  //2.1.5 判断是否是顶级类或接口等
                  if (isCandidateComponent(sbd)) {
                     if (debugEnabled) {
                        logger.debug("Identified candidate component class: " + resource);
                     }
                     candidates.add(sbd);
                  }
                  
               }
               
            }
            
         }
         
      }
   }
   ----去掉日志逻辑
   return candidates;
}

包名转换:把 . 转换成 /

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

// ClassUtils
private static final char PACKAGE_SEPARATOR = '.';
private static final char PATH_SEPARATOR = '/';

public static String convertClassNameToResourcePath(String className) {
    Assert.notNull(className, "Class name must not be null");
    return className.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
}

前缀是 classpath*: ,中间是将包名.转换为/,后缀默认扫 **/*.class

最终拼接包路径为:classpath*:com/small/**/*.class

2.1.2 获取资源解析器并加载资源

获取包路径资源解析器,这里的资源解析器在ClassPathBeanDefinitionScanner构造器1.1中就被创建了

private ResourcePatternResolver getResourcePatternResolver() {
   if (this.resourcePatternResolver == null) {
      this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
   }
   return this.resourcePatternResolver;
}
@Override
public Resource[] getResources(String locationPattern) throws IOException {
   if (this.resourceLoader instanceof ResourcePatternResolver) {
      return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern);
   }
   return super.getResources(locationPattern);
}

PathMatchingResourcePatternResolver加载资源

public Resource[] getResources(String locationPattern) throws IOException {
   Assert.notNull(locationPattern, "Location pattern must not be null");
   if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
      // a class path resource (multiple resources for same name possible)
      if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
         // a class path resource pattern
         return findPathMatchingResources(locationPattern);
      }
      
   }
  
}

整个方法的大if结构中,先判断要扫描的包路径是否有 classpath*: ,有则截掉,之后判断路径是否能匹配扫描规则。而这个规则的匹配器,通过IDEA发现 PathMatcher 只有一个实现类: AntPathMatcher ,由此也解释了 SpringFramework 支持的是ant规则声明包。

如果规则匹配,则会进入下面的 findPathMatchingResources 方法:

protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
   // 2.1.2.1 截取扫描根路径
   String rootDirPath = determineRootDir(locationPattern);
   String subPattern = locationPattern.substring(rootDirPath.length());
   // 2.1.2.2 获取扫描包路径下的所有包
   Resource[] rootDirResources = getResources(rootDirPath);
   Set<Resource> result = new LinkedHashSet<>(16);
   for (Resource rootDirResource : rootDirResources) {
      rootDirResource = resolveRootDirResource(rootDirResource);
      URL rootDirUrl = rootDirResource.getURL();
      if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
         URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
         if (resolvedUrl != null) {
            rootDirUrl = resolvedUrl;
         }
         rootDirResource = new UrlResource(rootDirUrl);
      }
      if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
         result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
      }
      else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
         result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
      }
      else {
          // 2.1.2.3查找路径匹配文件资源
         result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
      }
   }
   if (logger.isTraceEnabled()) {
      logger.trace("Resolved location pattern [" + locationPattern + "] to resources " + result);
   }
   return result.toArray(new Resource[0]);
}

2.1.2.1 截取扫描根路径

原来路径:classpath*:com/small/**/*.class

rootDirPath截取后根路径为:classpath*:com/small/

subPattern剩余路径为:**/*.class

protected String determineRootDir(String location) {
   int prefixEnd = location.indexOf(':') + 1;
   int rootDirEnd = location.length();
   while (rootDirEnd > prefixEnd && getPathMatcher().isPattern(location.substring(prefixEnd, rootDirEnd))) {
      rootDirEnd = location.lastIndexOf('/', rootDirEnd - 2) + 1;
   }
   if (rootDirEnd == 0) {
      rootDirEnd = prefixEnd;
   }
   return location.substring(0, rootDirEnd);
}

2.1.2.2 获取扫描包路径下的所有包

protected Resource[] findAllClassPathResources(String location) throws IOException {
   String path = location;
   if (path.startsWith("/")) {
      path = path.substring(1);
   }
   Set<Resource> result = doFindAllClassPathResources(path);
   if (logger.isTraceEnabled()) {
      logger.trace("Resolved classpath location [" + location + "] to resources " + result);
   }
   return result.toArray(new Resource[0]);
}

这里进行真正的扫描获取包的工作:doFindAllClassPathResources

protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
   Set<Resource> result = new LinkedHashSet<>(16);
   ClassLoader cl = getClassLoader();
   Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
   while (resourceUrls.hasMoreElements()) {
      URL url = resourceUrls.nextElement();
      result.add(convertClassLoaderURL(url));
   }
   if (!StringUtils.hasLength(path)) {
      // The above result is likely to be incomplete, i.e. only containing file system references.
      // We need to have pointers to each of the jar files on the classpath as well...
      addAllClassLoaderJarRoots(cl, result);
   }
   return result;
}

可以发现它在做的工作是使用类加载器,把传入的根包以Resource的形式加载出来,以便后续的文件读取

2.1.2.3查找路径匹配文件资源

获取目录资源的绝对路径:

例如:D:\java\gitee\我的项目\small-test\my-small-test\target\classes\com\small\autoConfig

rotected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
      throws IOException {

   File rootDir;
   try {
      rootDir = rootDirResource.getFile().getAbsoluteFile();
   }
   ......
   
   return doFindMatchingFileSystemResources(rootDir, subPattern);
}

做一些文件检查

protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException {
    // 不存在的检查
    if (!rootDir.exists()) {
        // log
        return Collections.emptySet();
    }
    // 非文件夹检查
    if (!rootDir.isDirectory()) {
        // log
        return Collections.emptySet();
    }
    // 不可读检查
    if (!rootDir.canRead()) {
        // log
        return Collections.emptySet();
    }
    String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");
    if (!pattern.startsWith("/")) {
        fullPattern += "/";
    }
    fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");
    Set<File> result = new LinkedHashSet<>(8);
    doRetrieveMatchingFiles(fullPattern, rootDir, result);
    return result;
}

doRetrieveMatchingFiles:递归扫描

使用递归扫描包路径下每个资源,当资源路径匹配全路径就说明是目标资源,将其加入结果集中

D:/java/gitee/我的项目/small-test/my-small-test/target/classes/com/small/**/*.class

protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException {
  if (logger.isTraceEnabled()) {
     logger.trace("Searching directory [" + dir.getAbsolutePath() +
           "] for files matching pattern [" + fullPattern + "]");
  }
  for (File content : listDirectory(dir)) {
     String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
     if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {
        if (!content.canRead()) {
           if (logger.isDebugEnabled()) {
              logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() +
                    "] because the application is not allowed to read the directory");
           }
        }
        else {
           doRetrieveMatchingFiles(fullPattern, content, result);
        }
     }
     //当资源路径匹配全路径就说明是目标资源,将其加入结果集中
     if (getPathMatcher().match(fullPattern, currPath)) {
        result.add(content);
     }
  }
}

2.1.3 包装resource并存入metadataReaderCache缓存中

public MetadataReader getMetadataReader(Resource resource) throws IOException {
   if (this.metadataReaderCache instanceof ConcurrentMap) {
      // No synchronization necessary...
      MetadataReader metadataReader = this.metadataReaderCache.get(resource);
      if (metadataReader == null) {
         //
         metadataReader = super.getMetadataReader(resource);
         //放入缓存
         this.metadataReaderCache.put(resource, metadataReader);
      }
      return metadataReader;
   }
   else if (this.metadataReaderCache != null) {
      synchronized (this.metadataReaderCache) {
         MetadataReader metadataReader = this.metadataReaderCache.get(resource);
         if (metadataReader == null) {
            metadataReader = super.getMetadataReader(resource);
            this.metadataReaderCache.put(resource, metadataReader);
         }
         return metadataReader;
      }
   }
   else {
      return super.getMetadataReader(resource);
   }
}

包装resource

public MetadataReader getMetadataReader(Resource resource) throws IOException {
   return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}

2.1.4 过滤、筛选Bean(可以在@ComponentScan注解中加)

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   //2.1.4.1遍历excludeFilters过滤器集合,如果匹配任何一个TypeFilter,则返回false,表示没资格
   for (TypeFilter tf : this.excludeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return false;
      }
   }
   //2.1.4.2遍历includeFilters过滤器集合,如果匹配任何一个TypeFilter,则返回true,表示有资格
   for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return isConditionMatch(metadataReader);
      }
   }
   return false;
}

2.1.4.1 排除过滤器

这里注入了三个排除类型过滤器

image.png

AbstractTypeHierarchyTraversingFilter,抽象方法,定义了 match 方法的模板,具体实现都交给子类实现

public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilter {

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

	// 是否考虑父类匹配
	private final boolean considerInherited;

	// 是否考虑接口匹配
	private final boolean considerInterfaces;

	protected AbstractTypeHierarchyTraversingFilter(boolean considerInherited, boolean considerInterfaces) {
		this.considerInherited = considerInherited;
		this.considerInterfaces = considerInterfaces;
	}

	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {

		// 提供了一个快速匹配的通道,可由子类复写
		if (matchSelf(metadataReader)) {
			return true;
		}

		// 类匹配,子类复写
		ClassMetadata metadata = metadataReader.getClassMetadata();
		if (matchClassName(metadata.getClassName())) {
			return true;
		}

		// 如果考虑父类匹配
		if (this.considerInherited) {
			String superClassName = metadata.getSuperClassName();
			if (superClassName != null) {
				Boolean superClassMatch = matchSuperClass(superClassName);
				if (superClassMatch != null) {
					if (superClassMatch.booleanValue()) {
						return true;
					}
				}
				else {
					try {
						// 递归匹配父类
						if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read super class [" + metadata.getSuperClassName() +
									"] of type-filtered class [" + metadata.getClassName() + "]");
						}
					}
				}
			}
		}

		// 接口匹配
		if (this.considerInterfaces) {
			for (String ifc : metadata.getInterfaceNames()) {
				Boolean interfaceMatch = matchInterface(ifc);
				if (interfaceMatch != null) {
					if (interfaceMatch.booleanValue()) {
						return true;
					}
				}
				else {
					try {
						if (match(ifc, metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
									metadata.getClassName() + "]");
						}
					}
				}
			}
		}

		return false;
	}

	// 略

}

2.1.4.2.1 ComponentScanAnnotationParser(排除启动类)

ComponentScanAnnotationParser在解析的时候添加了TypeFilter匿名实现类

scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
   @Override
   protected boolean matchClassName(String className) {
      //declaringClass为主启动类
      return declaringClass.equals(className);
   }
});

这个过滤器的作用是如果注入的资源是启动类就排除

2.1.4.2.2 AutoConfigurationExcludeFilter(排除配置类)
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
      throws IOException {
   return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);
}

如果当前资源含有@Configuration注解并且属于自动配置类(META-INF/spring.factories下EnableAutoConfiguration)则排除

2.1.4.2.2 TypeExcludeFilter(排除配置类)

判断Bean工厂是否ListableBeanFactory类型

public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
      throws IOException {
      //判断Bean工厂是否ListableBeanFactory类型
   if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {
      for (TypeExcludeFilter delegate : getDelegates()) {
         if (delegate.match(metadataReader, metadataReaderFactory)) {
            return true;
         }
      }
   }
   return false;
}

获取容器中所有TypeExcludeFilter实例进行过滤

private Collection<TypeExcludeFilter> getDelegates() {
   Collection<TypeExcludeFilter> delegates = this.delegates;
   if (delegates == null) {
      delegates = ((ListableBeanFactory) this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();
      this.delegates = delegates;
   }
   return delegates;
}

因为没有TypeExcludeFilter实例所以不会走过滤逻辑

2.1.4.2 包含过滤器

image.png

这里会有@Component和@ManagedBean两种AnnotationTypeFilter注解过滤器,满足其中一个条件则会将当前类加入结果集

protected boolean matchSelf(MetadataReader metadataReader) {
   AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
   return metadata.hasAnnotation(this.annotationType.getName()) ||
         (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}

判断条件(满足一个即可)

  • 如果类上含有@Component或者@ManagedBean
  • 如果类的注解元数据中含有@Component或者@ManagedBean

2.1.5 判断是否是顶级类或接口等

  • metadata.isIndependent() : 判断是否可以new
  • metadata.isConcrete() : 不能是接口也不能是抽象类
  • metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))) : 如果是抽象类但是这个抽象类内部有随便一个方法加了@Lookup注解(CGLIB的动态代理类就会实现这个方法)
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
   AnnotationMetadata metadata = beanDefinition.getMetadata();
   return (metadata.isIndependent() && (metadata.isConcrete() ||
         (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}

2.2解析作用域(参考1.3)

2.3设置Bean名称(参考1.2)

2.4 postProcessBeanDefinition 后置处理BeanDefinition

设置 BeanDefinition 的一些默认值

protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
   beanDefinition.applyDefaults(this.beanDefinitionDefaults);
   if (this.autowireCandidatePatterns != null) {
      beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
   }
}

2.5 processCommonDefinitionAnnotations 处理公共注解

处理@Lazy、@Primary、@DependsOn、@Role、@Description属性值,设置进BeanDefinition中

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
   AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
   if (lazy != null) {
      abd.setLazyInit(lazy.getBoolean("value"));
   }
   else if (abd.getMetadata() != metadata) {
      lazy = attributesFor(abd.getMetadata(), Lazy.class);
      if (lazy != null) {
         abd.setLazyInit(lazy.getBoolean("value"));
      }
   }

   if (metadata.isAnnotated(Primary.class.getName())) {
      abd.setPrimary(true);
   }
   AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
   if (dependsOn != null) {
      abd.setDependsOn(dependsOn.getStringArray("value"));
   }

   AnnotationAttributes role = attributesFor(metadata, Role.class);
   if (role != null) {
      abd.setRole(role.getNumber("value").intValue());
   }
   AnnotationAttributes description = attributesFor(metadata, Description.class);
   if (description != null) {
      abd.setDescription(description.getString("value"));
   }
}

2.6 checkCandidate 检查BeanName是否冲突

protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
   if (!this.registry.containsBeanDefinition(beanName)) {
      return true;
   }
   BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
   BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
   if (originatingDef != null) {
      existingDef = originatingDef;
   }
   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() + "]");
}

2.7 registerBeanDefinition 注册BeanDefinition

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   //获取Bean名称
   String beanName = definitionHolder.getBeanName();
   //放入beanDefinitionMap中
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   //注册Bean别名
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

总结

第一步、扫描包路径

  1. 拼凑包路径为:classpath*:com/small/**/*.class
  2. 截取出根路径:classpath*:com/small/
  3. 截取资源路径下包路径:com/small/
  4. 使用系统类加载器(AppClassLoader)通过资源包路径获取资源全路径:/D:/java/gitee/small-test/my-small-test/target/classes/com/small/
  5. 拼凑路径匹配:/java/gitee/我的项目/small-test/my-small-test/target/classes/com/small/**/*.class
  6. 递归扫描资源全路径与路径匹配做对比,如果匹配上说明是目标资源则加入结果集返回

第二步、过滤和筛选

  1. 排除启动类和自动配置类(含有@Config并且属于自动配置类(META-INF/spring.factories下EnableAutoConfiguration)
  2. 筛选出含有@Component和@ManagedBean注解的
  3. 筛选可创建的对象

第三步、处理Bean信息

  1. 作用域、名称、注解值等