Spring源码深度解析(六)——AnnotationConfigApplicationContext详解
程序员文章站
2024-02-27 12:10:39
...
今天的猪脚是AnnotationConfigApplicationContext,记着开始看这个类的时候已经是很久以前了,看起来简简单单几条代码,背后却是上万条。先来整体分析,然后后面再局部剖析。后面就简称为ACAC
ACAC到底是用来干嘛的
这个类就是我们常常提到的应用上下文,可以做这么说吧(个人理解),它包含Spring应用的所有信息(包括配置信息),它负责将Spring中零零散散的信息和功能整合起来。
说到ApplicationContext就不免能想到三种加载应用上下文的方式
- AnnotationConfigApplicationContext
- ClassPathXmlApplicationContext
- FileSystemXmlApplicationContext
ACAC是怎么执行的初始化
它有四种构造方法
- AnnotationConfigApplicationContext()
- AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory)
- AnnotationConfigApplicationContext(Class<?>… componentClasses)
- AnnotationConfigApplicationContext(String… basePackages)
- 无参构造:进行读取器和扫描器的初始化,在实例化前会调用父类的构造方法给BeanFactory赋值为DefaultListableBeanFactory
public AnnotationConfigApplicationContext() {
/**
* 实例化reader
* AnnotatedBeanDefinition 被注解的Bean
* 读取那些被加注解了的Bean
*/
this.reader = new AnnotatedBeanDefinitionReader(this);
/**
* 实例化一个scanner
* 能够扫描类,包,并转换为bd
* 这个scan存在的意义就是手动扫描,平时用的@ComponentScan并没有用这个scanner而是又重新new了一个ClassPathBeanDefinitionScanner
*/
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
// 父类GenericApplicationContext的无参构造
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
- 自己选择传入的BeanFactory
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
// 父类方法
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
- 带有一个或多个配置类的
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
//在this调用的无参构造方法,间接的调用了父类的无参构造初始化了BeanFactory
//在自己的构造方法中初始化一个读取器和一个扫描器
this();
//读取一个/多个类,并注册到map
register(componentClasses);
refresh();
}
- 带有包扫描的
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
由此可看,每对ApplicationContext进行一次添入操作(不论是配置文件还是普通类)都要进行refresh,如下代码,在上下文初始化话完成后进行了register操作没有进行refresh操作,就会报如下异常
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
System.out.println(applicationContext.getBean(AppConfig.class));
// 出现未refresh异常
> Task :My-Spring:AnnotationTest.main() FAILED
Exception in thread "main" java.lang.IllegalStateException: org.springaaa@qq.com4edde6e5 has not been refreshed yet
从此可以看出,refresh()的执行流程就是上下文的生命周期
ACAC的生命周期
鉴于上文测试,因此我将把refresh中的每一个非空方法作为一个生命流程
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//准备工作包括设置启动时间,**容器,获取当前环境验证标记是可以解析的
prepareRefresh();
// Tell the subclass to refresh the internal bean factory. 告诉子类刷新内部bean工厂
//得到DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//准备beanFactory 吧BeanFactory必须的一些组件放进去
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//里面没有任何代码,有待扩展
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//在Spring环境取执行已经注册的factory processors
//调用自定义(需要add进AnnotationConfigApplicationContext中的才算)的processorBeanFactory和spring自己定义的BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册bean processors
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 国际化
initMessageSource();
// Initialize event multicaster for this context.
//初始化应用事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 初始化一些特殊的Bean
onRefresh();
// Check for listener beans and register them.
// 注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 剩余的单例对象初始化 这个方法极为重要
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 公布上下文刷新事件
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
我花了一张图对它进行了流程分析,如下:
这个就是AnnotationConfigApplicationContext的生命周期,在接下来的文章里,将会对这些生命流程一个一个剖析!
上一篇: 新手关于I2C 的学习笔记
下一篇: I2C协议的理解
推荐阅读
-
Spring源码深度解析(六)——AnnotationConfigApplicationContext详解
-
Spring源码深度解析(四)——模拟mybatis和原理分析
-
String之PropertyPlaceholderConfigurery源码解析 博客分类: spring PropertyPlaceholderConfigurery源码详解使用
-
Spring源码深度解析(第2版)- 自定义标签的使用
-
Spring源码深度解析(第2版)- 时序图及源码(js-sequence-diagrams)
-
Spring源码深度解析(郝佳)-学习-元数据解析
-
spring AOP源码深度解析
-
spring源码深度解析——数据库连接JDBC(2)
-
Spring源码深度解析(十一)SpringMVC源码解析(三)参数绑定机制
-
spring5 源码深度解析----- AOP目标方法和增强方法的执行(100%理解AOP)