Spring源码学习---Bean对象扫描

SpringBean对象扫描过程,如下图。
Spring源码学习---Bean对象扫描_第1张图片
结合上图的流程和源码,简要分析一下Bean扫描的源码。

1 Bean对象的扫描入口

// Invoke factory processors registered as beans in the context.
// 调用在上下文中注册为 bean 的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);

@ComponentScan,提到spring扫描,离不开这个接口,那么它是如何工作的呢?这里就讲到Spring的refresh()方法,这个方法就是Spring源码的核心,里面包含了12个方法,今天说的Bean对象扫描入口就在其中的一个方法中。

/**
 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
 * respecting explicit order if given.
 * 

Must be called before singleton instantiation. */ protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); ... }

进入这个方法中,这里是利用beanFactoryPostProcessor(bean工厂的后置处理器)去完成的。再点击invokeBeanFactoryPostProcessors()方法进入。

for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
	if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
		BeanDefinitionRegistryPostProcessor registryProcessor =
				(BeanDefinitionRegistryPostProcessor) postProcessor;
		registryProcessor.postProcessBeanDefinitionRegistry(registry);
		registryProcessors.add(registryProcessor);
	}
	else {
		regularPostProcessors.add(postProcessor);
	}
}

这里根据获取的bean工厂的后置处理器,找到BeanDefinitionRegistry类型的处理器,去获取BeanDefinition对象,也就是Bean对象的前身。
bean工厂后置处理器很多,他们帮我们完成很多很多的工作,这里只是其中的一个,然后我们点击postProcessBeanDefinitionRegistry()方法进入。

/**
 * Derive further bean definitions from the configuration classes in the registry.
 */
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	processConfigBeanDefinitions(registry);
}

我们可以看到这个方法的定义是说,从注册表中的配置类派生更多的 beanDefinition对象。
系统先根据registry对象生成一个hashcode值,如果this.registriesPostProcessed(set集合)中存在,就抛出异常,提示已经调用过了,如果没有,则进入processConfigBeanDefinitions(registry)方法中。

/**
 * Build and validate a configuration model based on the registry of
 * {@link Configuration} classes.
 */
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	String[] candidateNames = registry.getBeanDefinitionNames();

	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}
	...
	// 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 {
		parser.parse(candidates);
		...
}

这个方法注释说,构建和认证配置模型基于配置类注册器,
方法中先获取配置类的BeanDefinitionHolder对象集合,再创建配置类解析器,去解析每一个配置类。我们点击parser.parse()方法。

for (BeanDefinitionHolder holder : configCandidates) {
	BeanDefinition bd = holder.getBeanDefinition();
	try {
		if (bd instanceof AnnotatedBeanDefinition) {
			parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
		}
		else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
			parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
		}
		else {
			parse(bd.getBeanClassName(), holder.getBeanName());
		}
	}
	...

进入parse()方法后,我们看到,for循环遍历配置类的BeanDefinitionHolder 对象,再根据配置类的类型(基于注解的,抽象的,其他的)分别去解析。
我们再点击parse()方法,
点击processConfigurationClass(new ConfigurationClass(metadata, beanName));方法,找到下面这段代码。

// Recursively process the configuration class and its superclass hierarchy.
// 递归处理配置类及其超类层次结构。
SourceClass sourceClass = asSourceClass(configClass);
do {
	sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);

接着点击doProcessConfigurationClass()方法,进入里面。

// 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());
		...
	}
}

这个方法就是读取类、方法上的注解,比如@ComponentScan@Bean@Component等,将这些构建为配置类,再解析成对应的beanDefinition对象。

因为篇幅有限,这里只粘贴处理@ComponentScan注解的代码,可以看到如果componentScans集合不为空,则遍历解析那些加了@ComponentScan注解的类。
我们进入parse()方法中。

2 构建ClassPathBeanDefinitionScanner扫描器

准备工作:

  • 构建扫描器,在构造方法中指定默认的includeFilters、注册表等属性,设置beanName的默认生成策略、范围代理属性和资源匹配模式等属性。
  • 获取包路径basePackages集合。
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
		componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
		BeanUtils.instantiateClass(generatorClass));
...
return scanner.doScan(StringUtils.toStringArray(basePackages));

2.1 beanName的生成策略

在上面的源码中,我们可以看到,先获取注解componentScan的“nameGenerator”属性值,这里如果你没有指定,那就是获取默认的BeanNameGenerator.class

Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

点击进入BeanNameGenerator.class中,这是个接口,进入它的注解实现类中,可以看到下面这个方法。

	@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		if (definition instanceof AnnotatedBeanDefinition) {
			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对象注解上有无beanName,如果有则直接返回,没有则进入buildDefaultBeanName()方法中生成唯一的默认beanName。

点进去,获取beanClassName,再进入到Introspector类中的decapitalize()方法里。

    public static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                        Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }

上面decapitalize()方法中,如果开头的第一个、第二个字母都是大写,那么就不做处理,直接返回;如果只是首字母大写,则首字母转为小写,然后返回。

3 开始扫描

点击scanner.doScan(),开始进入扫描方法。

Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
	Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
	for (BeanDefinition candidate : candidates) {
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
		candidate.setScope(scopeMetadata.getScopeName());
		...
		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;

doScan()方法中,根据basePackages包路径获取BeanDefinition集合,我们点击findCandidateComponents()方法,进入里面,这里提供两种扫描方式,一种是基于componentsIndex,这里我们看另外一种默认的方式:scanCandidateComponents(basePackage);点击这个方法,进入。

3.1 利用ASM技术读取类信息

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							candidates.add(sbd);
						}
						...
	}
	return candidates;
}

阅读上面这段源码,先拼接获取包路径;然后利用资源解析器去扫描路径下的所有Resource对象;如果资源对象可读,则利用元数据读取器工厂去获取当前传入资源的元数据读取器。

在获取类的元数据读取器时,用到ASM技术,它是asm包下的一个类属性获取技术,不同于jvm的反射,它不需要占用太多的jvm内存。

3.2 过滤元数据读取器

获取到元数据读取器后,还要经过两层判断:

  • 进行filter+条件注解(isConditionMatch)的判断
isCandidateComponent(metadataReader)

点击进入这个方法,可以看到:

	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		for (TypeFilter tf : this.excludeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return false;
			}
		}
		for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

这里就是对excludeFiltersincludeFilters过滤
isConditionMatch()方法是按指定条件去过滤,同时你也可以自己去实现Condition接口,重写里面的matches()方法,将你重写的类加到@Conditional注解中,按自己指定条件匹配对象。
这里就不做演示,感兴趣的可以自己去尝试一下。

  • 进行独立类、接口、抽象类、@Lookup的判断
isCandidateComponent(sbd)

点击进入下面的方法,这里判断当前扫描的类是否是独立类,即类的获取不需要依赖其他类,比如内部类就不是独立类(静态内部类除外)
判断类既不是接口也不是抽象的,如果是则返回true;如果不是,则判断类是抽象的且其中有方法上有@Lookup注解的,也返回true。

	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
		AnnotationMetadata metadata = beanDefinition.getMetadata();
		return (metadata.isIndependent() && (metadata.isConcrete() ||
				(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
	}

获取到的BeanDefinition集合返回到doScan()方法。

3.3 给BeanDefinition对象设置注解属性

if (candidate instanceof AnnotatedBeanDefinition) {
	AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}

点击进入processCommonDefinitionAnnotations()方法,

	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"));
		}
	}

这个方法就是给当前的BeanDefinition对象设置各种注解属性,如果有的话。

3.4 判断BeanDefinition对象是否重复

找到checkCandidate(beanName, candidate)方法,进入这个方法中,找到isCompatible()方法,这个就是判断生成的bean对象是否重复。

// 确定给定的新 bean 定义是否与给定的现有 bean 定义兼容
if (isCompatible(beanDefinition, existingDef)) {
	return false;
}

最后将BeanDefinition对象集合返回,做下一步的处理。

你可能感兴趣的:(源码,Java学习,spring,java,spring源码,Bean对象扫描)