概述
spring源码解析【配置文件——完整bean对象】
- 流程图
- 解析
流程图
解析
一,spring是如何加载配置文件到应用程序的?
我们写过xml或者properties等这样的配置文件,那究竟是spring是如何加载的,首先我们从这里去看,想一个问题,各配置文件不同,那么是否需要统一一个规范,去实现读取不同的配置文件?是的,spring提供了这样一个抽象接口,BeanDefinitionReader;
在这个接口下有两个子类,从名字开头相信大家应该能明白了吧,这里要注意源码注释里,BeanDefinitionReader是一个阅读器;读取了这些bean定义信息,它就是一个BeanDefinittion,那么既然是一个阅读器,只是一个阅读,那么想一个问题?我们在xml里定义了一个bean,如下:
<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个方法;
@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源码解析(一)】流程图所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复