Bean的生命周期,就是从创建Bean到销毁Bean的过程。在这个过程中,Spring提供了很多扩展点,这些扩展点具象化的表示就是各种BeanPostProcessor(Bean的后置处理器)的实现。本篇主要的内容就是介绍扫描Bean、实例化Bean、销毁Bean以及中间夹杂着执行各种Bean的后置处理器的过程。
下面的流程图包括了Bean的整个生命周期,对于ApplicationContext容器,所有的非懒加载的单例Bean都是在容器启动时创建的,因此Bean的整个生命周期的绝大多数过程都是在容器启动时发生的。容器启动时首先创建并初始化BeanFactory,随后执行一些特定的BeanFactoryPostProcessor(BeanFactory后置处理器)方法,其中就包括执行扫描包路径逻辑的ConfigurationClassPostProcessor类,今天的介绍也从该类开始。
扫描生成BeanDefinition
ConfigurationClassPostProcessor类最主要的功能是解析配置类,扫描过程是在其解析配置类上的@ComponentScan注解后进行的,关于容器启动和解析配置类在其他部分已经详细介绍过,此处不再赘述。最终执行扫描逻辑的是ClassPathBeanDefinitionScanner类的doScan()方法。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
//遍历扫描从@ComponentScan注解得到的所有包路径
for (String basePackage : basePackages) {
//findCandidateComponents()方法执行扫描逻辑并将扫描到的Bean解析生成BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
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) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查Spring容器中是否已经存在该beanName
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 将生成的BeanDefinition注册到BeanFactory
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
doScan()方法主要是扫描从配置类上的@ComponentScan注解得到的所有包路径,将得到的Bean生成BeanDefinition,最后将其注册到BeanFactory中以便于后面随时对Bean进行实例化。此方法中的核心方法是findCandidateComponents()方法。
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
在findCandidateComponents()中,一般情况下进入的是scanCandidateComponents()方法。
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 获取basePackage下所有的文件资源
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 {
//1.通过元数据读取器读取资源文件的元数据
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 2.根据excludeFilters、includeFilters判断BeanDefinition是否是Bean
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
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);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}