Spring Bean 的生命周期

1,114 阅读4分钟

概述

Bean 的初始化学习,我们先梳理一下 Spring Bean 初始化过程的步骤

  1. 源码入口 AnnotationConfigApplicationContext#refresh()
// 执行 BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);

// 进入实现(快捷键:ctrl + alt + b )
// AbstractApplicationContext#invokeBeanFactoryPostProcessors
// 1. 执行 BeanFactoryPostProcessors 的方法
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

Spring Bean 的创建过程

1. BeanDefinition 获取 Bean 定义信息

  • 定义配置类和扫描的路径/扫描的包
// 定义配置类和扫描的路径/扫描的包
@Configuration
@ComponentScan("cn.edu.cqvie.service")
class AppConfig {

	@Bean
	public UserService userService200() {
		return new UserService();
	}
}

  • 生成 BeanDefinition 对象入口, 按照这个入口结构可以方便我们调试
//生成 BeanDefinition 对象入口
AnnotationConfigApplicationContext#refresh()
-- AbstractApplicationContext#invokeBeanFactoryPostProcessors(..);
  -- PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(..);
    -- PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors(..)
       -- ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(..)
       --   processConfigBeanDefinitions(..)
         -- ConfigurationClassParser#parse(..)
         --   processConfigurationClass(..)
         --   doProcessConfigurationClass(..)
           -- ComponentScanAnnotationParser#parse(..)
             -- ClassPathBeanDefinitionScanner#doScan(..)
             -- findCandidateComponents(..)
             -- scanCandidateComponents(..)
             // 扫描包: Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);` 
             // 最终返回  Set<BeanDefinition> 生成 BeanDefinition 
  • 扫描方法 scanCandidateComponents 解析
    1). 扫描包获取到 Resource 数组
    2). 遍历 Resource 数组然后生成通过 ASM 模块获取 MetadataReader 对象获取 class 上的元信息和注解信息
    3). 然后通过 isCandidateComponent(..) 方法判断该 class 文件是否包含 @Component 信息,或者说是否是一个 Bean
    4). 如果通过检查则将它加入到 candidates 中去并且返回。

// 扫描方法
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    //扫描类,得到 BeanDefinition
    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 包含了对应的 class 的元信息以及注解信息, MetadataReader
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    //判断是否是 Component
                    if (isCandidateComponent(metadataReader)) {
                        //通过扫描 @Component 得到 BeanDefinition为 ScannedGenericBeanDefinition
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        //再次验证是否是 Component
                        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;
}

2. 合并 BeanDefinition

如果某个 BeanDefinition 存在父 BeanDefinition, 那么则要进行合并

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

3. 加载类

  1. 如果当前类不是懒加载,且是单例 Bean 我们就去加载类
// 方法入口
AbstractAutowireCapableBeanFactory#createBean(..) {
	// 加载类
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
}
  1. 类加载方法 resolveBeanClass 的实现
if (mbd.hasBeanClass()) {
	return mbd.getBeanClass();
}
if (System.getSecurityManager() != null) {
	return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
		doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}
else {
	return doResolveBeanClass(mbd, typesToMatch);
}

4. 实例化前置方法

Spring 允许第三方自定义 Bean 创建过程的拓展方式,可以利用 InstantiationAwareBeanPostProcessorspostProcessBeforeInstantiation 来实现 Bean 的创建,已经结束默认的创建过程。

5. 推断构造方法

后续拓展单独来写

6. 实例化

通过构造方法反射获取到一个 Bean 的实例

// 方法入口
SimpleInstantiationStrategy#instantiate()

// 获取实例
return BeanUtils.instantiateClass(constructorToUse);

7. BeanDefinition 的后置处理

BeanDefintion 后置处理方法

// 方法入口
AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors(...)

执行 BeanDefinition 逻辑的代码

for (BeanPostProcessor bp : getBeanPostProcessors()) {
	if (bp instanceof MergedBeanDefinitionPostProcessor) {
		MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
		bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
	}
}

8. 属性填充

后续拓展单独来写

9. 执行Aware

我们常用到的 ApplicationContextAware 有主要有 BeanNameAwareEmbeddedValueResolverAwareApplicationContextAwareMessageSourceAware 我个人用到的比较多的就是 ApplicationContextAware 举个例子:

  1. 通常我们项目中有一个工具类 ApplicationContextUtil,通过 Spring Aware 拓展,可以提供拿到 bean 容器 ApplicationContext,最后可以获取到到目标 Bean。
  2. 我们可以使用下面的方式,代码实例
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
    private static ApplicationContext context;
 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
    
    public static ApplicationContext getApplicationContext() {
        return context;
    }
}

//调用方法,如果已经注册UserServie
UserService userSerivce = ApplicationContextUtil.getApplicationContext().getBean(UserServie.class);

Aware 的逻辑如下:

private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

10. 初始化前

这里需要注意的是在 BeanPostProcessorpostProcessBeforeInitialization 的方法中如果返回 null 那么后续的 Bean 后置处理器就不会被执行。

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // bpp1 => bpp2 ==> bpp3 (这里相当于是一个过滤器)
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

11. 初始化

初始化过程中主要是做了一个判断,如果当前 Bean 实现了 InitializingBean 接口那么将调用 Bean 的初始化方法 afterPropertiesSet()

((InitializingBean) bean).afterPropertiesSet();

12. 初始化后

Bean 初始化后,执行 Bean 后置处理器 postProcessAfterInitialization 方法

for (BeanPostProcessor processor : getBeanPostProcessors()) {
	Object current = processor.postProcessAfterInitialization(result, beanName);
	if (current == null) {
		return result;
	}
	result = current;
}

Bean 的销毁过程

上面我们讲到了 Spring Bean 的初始化,那么我们现在来看看 Spring Bean 销毁过程。这里由于 Bean 有两种模式:单例模式和原型模式,原型模式没有被 IOC 管理在实用完过后,由 GC 回收。单例模式被 IOC 容器缓存那么被创建单例实例 Bean 的生命周期就是在被创建后知道 IOC 容器关闭的这个过程,所以 Bean 销毁的核心就是 Bean 容器的关闭过程。
我们可以通过下面的代码来关闭容器。

//关闭 ioc 容器
applicationContext.close();

1. 容器关闭

2. 发布 ContextCloseEvnet 事件

3. 调用 LifecycleProcessor 的 onClose 方法

4. 销毁单例 Bean

  1. 找出所有的 Disposable Bean (实现了 DisposableBean 接口的 Bean)
  2. 遍历每个 DisposableBean Bean
  3. 找出它所依赖的 Bean ,并且将这些 Bean 在单例池中移除掉。
  4. 调用 DisposableBean 的 destroy() 方法
  5. 找到当前 DisposableBean 所包含的 inner beans ,将这些 Bean 从单例池中移除掉。

初始化和销毁拓展方法

@PostConstruct@PreDestroy 注解主要是用来实现在 Bean 初始化过后,和 Bean 被销毁的时候执行的拓展方法。比如:比如我需要把某个 Bean 初始化后赋值给一个 static field 就可以通过 @PostConstruct 方式来完成,比如关闭 socket session 就可以在 @PreDestroy 来完成。代码示例:

/**
 * 初始化方法
 */
@PostConstruct
public void init() {
	System.out.println("int invoke!");
}

/**
 * 销毁方法方法
 */
@PreDestroy
public void destroy() {
	System.out.println("destroy invoke!");
}

Spring 源码解析