spring源码解析【配置文件——完整bean对象】
- 流程图
- 解析
流程图
解析
一,spring是如何加载配置文件到应用程序的?
我们写过xml或者properties等这样的配置文件,那究竟是spring是如何加载的,首先我们从这里去看,想一个问题,各配置文件不同,那么是否需要统一一个规范,去实现读取不同的配置文件?是的,spring提供了这样一个抽象接口,BeanDefinitionReader;
在这个接口下有两个子类,从名字开头相信大家应该能明白了吧,这里要注意源码注释里,BeanDefinitionReader是一个阅读器;读取了这些bean定义信息,它就是一个BeanDefinittion,那么既然是一个阅读器,只是一个阅读,那么想一个问题?我们在xml里定义了一个bean,如下:
1
2
3
4
5<bean id=? class=? > <constructor name=username value=${username}> <constructor name=password value=${password}> </bean>
这种写法肯定会有人见过,然后再再进行实例化的过程中,那么这个${}怎么办?肯定会变成对应的值,不然没办法做,所以在这里,我们需要知道两个经常面试会问道的问题:BeanFactoryPostProcessor和
BeanPostProcessor之间的区别?BeanFactoryPostProcessor:是处理BeanFactory的,而BeanPostProcessor是处理Bean的;
看到这里,我们再回想一下,读取了这些bean定义信息,它就变成一个BeanDefinition,那么谁来处理
它?
所以这个过程由BeanFactoryPostProcessor来处理,那么在这个接口一定会有一个子类来处理这些占位符,所以这里出现了一个叫PlaceholderConfigurerSupport的抽象类,其作用就是,解决占位符,来看源码的解释:
接下来实例化bean,再到完整的bean对象,再到销毁,其实也就是我们面试经常会被问到的,bean的生命周期?,源码中有一套标准:
在AbstractApplicationContext这里面,有一个很重要的方法: refresh();里面有13个方法;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); // Prepare this context for refreshing. //准备此上下文以进行刷新 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //告诉子类刷新内部 bean 工厂。 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //准备在此上下文中使用的 bean 工厂。 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //允许在上下文子类中对 bean 工厂进行后处理。 postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // Invoke factory processors registered as beans in the context. //调用在上下文中注册为 bean 的工厂处理器。 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //注册拦截 bean 创建的 bean 处理器。 registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // 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. //检查侦听器 bean 并注册它们。 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... //重置 Spring 核心中的常见内省缓存 resetCommonCaches(); contextRefresh.end(); } } }
我们重点来看的是finishBeanFactoryInitialization(beanFactory) 这个方法;
这个方法内有一个:
是用来实例化剩下的单例的,在这个方法内,会先经过这样一个过程:
会将beanDefinitionNames放在一个list集合中,循环遍历完成实例化对象,比如xml文件中的两个bean,
其中getMergedLocalBeanDefinition先拿BeanDefinition描述信息,先判断,如果没有拿到,先去创建CreateBean,而真正执行的是doCreateBean,createBeanInstance 实例化对象,先创建constructorg构造器,然后instantiateBean实例化bean;
在进入Instantiateclass中有一个ctor.newInstance开始反射,返回的就是相对应的对象,然后在进入populatebean: 其作用就是进行填充对象的属性值
完了进行aware,再然后就是before,再进行init方法,也就是invokeInitMethods 这个方法:
下一步就是执行after方法,执行完就返回了完整的bean对象;到此大概这个生命周期就是如此,当然还会有销毁的状态,销毁在这里不说。
以上一个大概就是spring中从配置文件读取bean再到bean的一个实例化和初始化的过程,很粗糙,但是希望对大家的一个大概思路有启发,明白了大体思路剩下的细节就慢慢扣吧;
留一个小问题:返回完整的bean对象最终放在哪里了?
最后
以上就是自由鼠标最近收集整理的关于【spring源码解析(一)】流程图的全部内容,更多相关【spring源码解析(一)】流程图内容请搜索靠谱客的其他文章。
发表评论 取消回复