概述
Bean 的初始化学习,我们先梳理一下 Spring Bean 初始化过程的步骤
- 源码入口 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. 加载类
- 如果当前类不是懒加载,且是单例 Bean 我们就去加载类
// 方法入口
AbstractAutowireCapableBeanFactory#createBean(..) {
// 加载类
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
}
- 类加载方法 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 创建过程的拓展方式,可以利用 InstantiationAwareBeanPostProcessors 的 postProcessBeforeInstantiation 来实现 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 有主要有
BeanNameAware、 EmbeddedValueResolverAware、ApplicationContextAware、MessageSourceAware
我个人用到的比较多的就是 ApplicationContextAware 举个例子:
- 通常我们项目中有一个工具类
ApplicationContextUtil,通过Spring Aware拓展,可以提供拿到 bean 容器ApplicationContext,最后可以获取到到目标 Bean。 - 我们可以使用下面的方式,代码实例
@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. 初始化前
这里需要注意的是在 BeanPostProcessor 的 postProcessBeforeInitialization 的方法中如果返回 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
- 找出所有的 Disposable Bean (实现了 DisposableBean 接口的 Bean)
- 遍历每个 DisposableBean Bean
- 找出它所依赖的 Bean ,并且将这些 Bean 在单例池中移除掉。
- 调用 DisposableBean 的 destroy() 方法
- 找到当前 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!");
}