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); }
2. 类加载方法 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!"); }