SpringIOC容器源码分析
Spring最重要的概念是IOC和AOP,本篇文章其实就是要带领大家来分析下Spring的IOC容器。既然大家平时都要用到Spring,怎么可以不好好了解Spring呢?阅读本文并不能让你成为Spring专家,不过一定有助于大家理解Spring的很多概念,帮助大家排查应用中和Spring相关的一些问题。
本文采用的源码版本是4。3。11。RELEASE,算是5。0。x前比较新的版本了。为了降低难度,本文所说的所有的内容都是基于xml的配置的方式,实际使用已经很少人这么做了,至少不是纯xml配置,不过从理解源码的角度来看用这种方式来说无疑是最合适的。
阅读建议:读者至少需要知道怎么配置Spring,了解Spring中的各种概念,少部分内容我还假设读者使用过SpringMVC。本文要说的IOC总体来说有两处地方最重要,一个是创建Bean容器,一个是初始化Bean,如果读者觉得一次性看完本文压力有点大,那么可以按这个思路分两次消化。读者不一定对Spring容器的源码感兴趣,也许附录部分介绍的知识对读者有些许作用。
希望通过本文可以让读者不惧怕阅读Spring源码,也希望大家能反馈表述错误或不合理的地方。
引言
先看下最基本的启动Spring容器的例子:
java
publicstaticvoidmain(String〔〕args){
ApplicationContextcontextnewClassPathXmlApplicationContext(classpath:applicationfile。xml);
}
以上代码就可以利用配置文件来启动一个Spring容器了,请使用maven的小伙伴直接在dependencies中加上以下依赖即可,个人比较反对那些不知道要添加什么依赖,然后把Spring的所有相关的东西都加进来的方式。
java
org。springframework
springcontextartifactId
4。3。11。RELEASE
dependency
springcontext会自动将springcore、springbeans、springaop、springexpression这几个基础jar包带进来。
多说一句,很多开发者入门就直接接触的SpringMVC,对Spring其实不是很了解,Spring是渐进式的工具,并不具有很强的侵入性,它的模块也划分得很合理,即使你的应用不是web应用,或者之前完全没有使用到Spring,而你就想用Spring的依赖注入这个功能,其实完全是可以的,它的引入不会对其他的组件产生冲突。
废话说完,我们继续。ApplicationContextcontextnewClassPathXmlApplicationContext(。。。)其实很好理解,从名字上就可以猜出一二,就是在ClassPath中寻找xml配置文件,根据xml文件内容来构建ApplicationContext。当然,除了ClassPathXmlApplicationContext以外,我们也还有其他构建ApplicationContext的方案可供选择,我们先来看看大体的继承结构是怎么样的:
!〔1〕(https:www。javadoop。comblogimagesspringcontext1。png)
读者可以大致看一下类名,源码分析的时候不至于找不着看哪个类,因为Spring为了适应各种使用场景,提供的各个接口都可能有很多的实现类。对于我们来说,就是揪着一个完整的分支看完。
当然,读本文的时候读者也不必太担心,每个代码块分析的时候,我都会告诉读者我们在说哪个类第几行。
我们可以看到,ClassPathXmlApplicationContext兜兜转转了好久才到ApplicationContext接口,同样的,我们也可以使用绿颜色的FileSystemXmlApplicationContext和AnnotationConfigApplicationContext这两个类。
1、FileSystemXmlApplicationContext的构造函数需要一个xml配置文件在系统中的路径,其他和ClassPathXmlApplicationContext基本上一样。
2、AnnotationConfigApplicationContext是基于注解来使用的,它不需要配置文件,采用java配置类和各种注解来配置,是比较简单的方式,也是大势所趋吧。
不过本文旨在帮助大家理解整个构建流程,所以决定使用ClassPathXmlApplicationContext进行分析。
我们先来一个简单的例子来看看怎么实例化ApplicationContext。
首先,定义一个接口:
java
publicinterfaceMessageService{
StringgetMessage();
}
定义接口实现类:
java
publicclassMessageServiceImplimplementsMessageService{
publicStringgetMessage(){
returnhelloworld;
}
}
接下来,我们在resources目录新建一个配置文件,文件名随意,通常叫application。xml或applicationxxx。xml就可以了:
xml
lt;?xmlversion1。0encodingUTF8?
beansxmlns:xsihttp:www。w3。org2001XMLSchemainstance
xmlnshttp:www。springframework。orgschemabeans
xsi:schemaLocationhttp:www。springframework。orgschemabeanshttp:www。springframework。orgschemabeansspringbeans。xsddefaultautowirebyName
beans
这样,我们就可以跑起来了:
java
publicclassApp{
publicstaticvoidmain(String〔〕args){
用我们的配置文件来启动一个ApplicationContext
ApplicationContextcontextnewClassPathXmlApplicationContext(classpath:application。xml);
System。out。println(context启动成功);
从context中取出我们的Bean,而不是用newMessageServiceImpl()这种方式
MessageServicemessageServicecontext。getBean(MessageService。class);
这句将输出:helloworld
System。out。println(messageService。getMessage());
}
}
以上例子很简单,不过也够引出本文的主题了,就是怎么样通过配置文件来启动Spring的ApplicationContext?也就是我们今天要分析的IOC的核心了。ApplicationContext启动过程中,会负责创建实例Bean,往各个Bean中注入依赖等。
BeanFactory简介
BeanFactory,从名字上也很好理解,生产bean的工厂,它负责生产和管理各个bean实例。
初学者可别以为我之前说那么多和BeanFactory无关,前面说的ApplicationContext其实就是一个BeanFactory。我们来看下和BeanFactory接口相关的主要的继承结构:
!〔2〕(https:www。javadoop。comblogimagesspringcontext2。png)
我想,大家看完这个图以后,可能就不是很开心了。ApplicationContext往下的继承结构前面一张图说过了,这里就不重复了。这张图呢,背下来肯定是不需要的,有几个重点和大家说明下就好。
1。ApplicationContext继承了ListableBeanFactory,这个Listable的意思就是,通过这个接口,我们可以获取多个Bean,大家看源码会发现,最顶层BeanFactory接口的方法都是获取单个Bean的。
2。ApplicationContext继承了HierarchicalBeanFactory,Hierarchical单词本身已经能说明问题了,也就是说我们可以在应用中起多个BeanFactory,然后可以将各个BeanFactory设置为父子关系。
3。AutowireCapableBeanFactory这个名字中的Autowire大家都非常熟悉,它就是用来自动装配Bean用的,但是仔细看上图,ApplicationContext并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到ApplicationContext接口定义中的最后一个方法getAutowireCapableBeanFactory()就知道了。
4。ConfigurableListableBeanFactory也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而ApplicationContext没有。这点之后会用到。
5。请先不用花时间在其他的接口和类上,先理解我说的这几点就可以了。
然后,请读者打开编辑器,翻一下BeanFactory、ListableBeanFactory、HierarchicalBeanFactory、AutowireCapableBeanFactory、ApplicationContext这几个接口的代码,大概看一下各个接口中的方法,大家心里要有底,限于篇幅,我就不贴代码介绍了。
启动过程分析
下面将会是冗长的代码分析,记住,一定要自己打开源码来看,不然纯看是很累的。
第一步,我们肯定要从ClassPathXmlApplicationContext的构造方法说起。
java
publicclassClassPathXmlApplicationContextextendsAbstractXmlApplicationContext{
privateResource〔〕configResources;
如果已经有ApplicationContext并需要配置成父子关系,那么调用这个构造方法
publicClassPathXmlApplicationContext(ApplicationContextparent){
super(parent);
}
。。。
publicClassPathXmlApplicationContext(String〔〕configLocations,booleanrefresh,ApplicationContextparent)
throwsBeansException{
super(parent);
根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
setConfigLocations(configLocations);
if(refresh){
refresh();核心方法
}
}
。。。
}
接下来,就是refresh(),这里简单说下为什么是refresh(),而不是init()这种名字的方法。因为ApplicationContext建立起来以后,其实我们是可以通过调用refresh()这个方法重建的,refresh()会将原来的ApplicationContext销毁,然后再重新执行一次初始化操作。
往下看,refresh()方法里面调用了那么多方法,就知道肯定不简单了,请读者先看个大概,细节之后会详细说。
java
Override
publicvoidrefresh()throwsBeansException,IllegalStateException{
来个锁,不然refresh()还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized(this。startupShutdownMonitor){
准备工作,记录下容器的启动时间、标记已启动状态、处理配置文件中的占位符
prepareRefresh();
这步比较关键,这步完成后,配置文件就会解析成一个个Bean定义,注册到BeanFactory中,
当然,这里说的Bean还没有初始化,只是配置信息都提取出来了,
注册也只是将这些信息都保存到了注册中心(说到底核心是一个beanNamebeanDefinition的map)
ConfigurableListableBeanFactorybeanFactoryobtainFreshBeanFactory();
设置BeanFactory的类加载器,添加几个BeanPostProcessor,手动注册几个特殊的bean
这块待会会展开说
prepareBeanFactory(beanFactory);
try{
【这里需要知道BeanFactoryPostProcessor这个知识点,Bean如果实现了此接口,
那么在容器初始化以后,Spring会负责调用里面的postProcessBeanFactory方法。】
这里是提供给子类的扩展点,到这里的时候,所有的Bean都加载、注册完成了,但是都还没有初始化
具体的子类可以在这步的时候添加一些特殊的BeanFactoryPostProcessor的实现类或做点什么事
postProcessBeanFactory(beanFactory);
调用BeanFactoryPostProcessor各个实现类的postProcessBeanFactory(factory)方法
invokeBeanFactoryPostProcessors(beanFactory);
注册BeanPostProcessor的实现类,注意看和BeanFactoryPostProcessor的区别
此接口两个方法:postProcessBeforeInitialization和postProcessAfterInitialization
两个方法分别在Bean初始化之前和初始化之后得到执行。注意,到这里Bean还没初始化
registerBeanPostProcessors(beanFactory);
初始化当前ApplicationContext的MessageSource,国际化这里就不展开说了,不然没完没了了
initMessageSource();
初始化当前ApplicationContext的事件广播器,这里也不展开了
initApplicationEventMulticaster();
从方法名就可以知道,典型的模板方法(钩子方法),
具体的子类可以在这里初始化一些特殊的Bean(在初始化singletonbeans之前)
onRefresh();
注册事件监听器,监听器需要实现ApplicationListener接口。这也不是我们的重点,过
registerListeners();
重点,重点,重点
初始化所有的singletonbeans
(lazyinit的除外)
finishBeanFactoryInitialization(beanFactory);
最后,广播事件,ApplicationContext初始化完成
finishRefresh();
}
catch(BeansExceptionex){
if(logger。isWarnEnabled()){
logger。warn(Exceptionencounteredduringcontextinitialization
cancellingrefreshattempt:ex);
}
Destroyalreadycreatedsingletonstoavoiddanglingresources。
销毁已经初始化的singleton的Beans,以免有些bean会一直占用资源
destroyBeans();
Resetactiveflag。
cancelRefresh(ex);
把异常往外抛
throwex;
}
finally{
ResetcommonintrospectioncachesinSpringscore,sincewe
mightnoteverneedmetadataforsingletonbeansanymore。。。
resetCommonCaches();
}
}
}
下面,我们开始一步步来肢解这个refresh()方法。
创建Bean容器前的准备工作
这个比较简单,直接看代码中的几个注释即可。
java
protectedvoidprepareRefresh(){
记录启动时间,
将active属性设置为true,closed属性设置为false,它们都是AtomicBoolean类型
this。startupDateSystem。currentTimeMillis();
this。closed。set(false);
this。active。set(true);
if(logger。isInfoEnabled()){
logger。info(Refreshingthis);
}
Initializeanyplaceholderpropertysourcesinthecontextenvironment
initPropertySources();
校验xml配置文件
getEnvironment()。validateRequiredProperties();
this。earlyApplicationEventsnewLinkedHashSet();
}
创建Bean容器,加载并注册Bean
我们回到refresh()方法中的下一行obtainFreshBeanFactory()。
注意,这个方法是全文最重要的部分之一,这里将会初始化BeanFactory、加载Bean、注册Bean等等。
当然,这步结束后,Bean并没有完成初始化。这里指的是Bean实例并未在这一步生成。
AbstractApplicationContext。java
java
protectedConfigurableListableBeanFactoryobtainFreshBeanFactory(){
关闭旧的BeanFactory(如果有),创建新的BeanFactory,加载Bean定义、注册Bean等等
refreshBeanFactory();
返回刚刚创建的BeanFactory
ConfigurableListableBeanFactorybeanFactorygetBeanFactory();
if(logger。isDebugEnabled()){
logger。debug(BeanfactoryforgetDisplayName():beanFactory);
}
returnbeanFactory;
}
AbstractRefreshableApplicationContext。java120
java
Override
protectedfinalvoidrefreshBeanFactory()throwsBeansException{
如果ApplicationContext中已经加载过BeanFactory了,销毁所有Bean,关闭BeanFactory
注意,应用中BeanFactory本来就是可以多个的,这里可不是说应用全局是否有BeanFactory,而是当前
ApplicationContext是否有BeanFactory
if(hasBeanFactory()){
destroyBeans();
closeBeanFactory();
}
try{
初始化一个DefaultListableBeanFactory,为什么用这个,我们马上说。
DefaultListableBeanFactorybeanFactorycreateBeanFactory();
用于BeanFactory的序列化,我想不部分人应该都用不到
beanFactory。setSerializationId(getId());
下面这两个方法很重要,别跟丢了,具体细节之后说
设置BeanFactory的两个配置属性:是否允许Bean覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);
加载Bean到BeanFactory中
loadBeanDefinitions(beanFactory);
synchronized(this。beanFactoryMonitor){
this。beanFactorybeanFactory;
}
}
catch(IOExceptionex){
thrownewApplicationContextException(IOerrorparsingbeandefinitionsourceforgetDisplayName(),ex);
}
}
看到这里的时候,我觉得读者就应该站在高处看ApplicationContext了,ApplicationContext继承自BeanFactory,但是它不应该被理解为BeanFactory的实现类,而是说其内部持有一个实例化的BeanFactory(DefaultListableBeanFactory)。以后所有的BeanFactory相关的操作其实是委托给这个实例来处理的。
我们说说为什么选择实例化DefaultListableBeanFactory?前面我们说了有个很重要的接口ConfigurableListableBeanFactory,它实现了BeanFactory下面一层的所有三个接口,我把之前的继承图再拿过来大家再仔细看一下:
!〔3〕(https:www。javadoop。comblogimagesspringcontext3。png)
我们可以看到ConfigurableListableBeanFactory只有一个实现类DefaultListableBeanFactory,而且实现类DefaultListableBeanFactory还通过实现右边的AbstractAutowireCapableBeanFactory通吃了右路。所以结论就是,最底下这个家伙DefaultListableBeanFactory基本上是最牛的BeanFactory了,这也是为什么这边会使用这个类来实例化的原因。
如果你想要在程序运行的时候动态往SpringIOC容器注册新的bean,就会使用到这个类。那我们怎么在运行时获得这个实例呢?
之前我们说过ApplicationContext接口能获取到AutowireCapableBeanFactory,就是最右上角那个,然后它向下转型就能得到DefaultListableBeanFactory了。
那怎么拿到ApplicationContext实例呢?如果你不会,说明你没用过Spring。
在继续往下之前,我们需要先了解BeanDefinition。我们说BeanFactory是Bean容器,那么Bean又是什么呢?
这里的BeanDefinition就是我们所说的Spring的Bean,我们自己定义的各个Bean其实会转换成一个个BeanDefinition存在于Spring的BeanFactory中。
所以,如果有人问你Bean是什么的时候,你要知道Bean在代码层面上可以简单认为是BeanDefinition的实例。
BeanDefinition中保存了我们的Bean信息,比如这个Bean指向的是哪个类、是否是单例的、是否懒加载、这个Bean依赖了哪些Bean等等。
BeanDefinition接口定义
我们来看下BeanDefinition的接口定义:
java
publicinterfaceBeanDefinitionextendsAttributeAccessor,BeanMetadataElement{
我们可以看到,默认只提供sington和prototype两种,
很多读者可能知道还有request,session,globalSession,application,websocket这几种,
不过,它们属于基于web的扩展。
StringSCOPESINGLETONConfigurableBeanFactory。SCOPESINGLETON;
StringSCOPEPROTOTYPEConfigurableBeanFactory。SCOPEPROTOTYPE;
比较不重要,直接跳过吧
intROLEAPPLICATION0;
intROLESUPPORT1;
intROLEINFRASTRUCTURE2;
设置父Bean,这里涉及到bean继承,不是java继承。请参见附录的详细介绍
一句话就是:继承父Bean的配置信息而已
voidsetParentName(StringparentName);
获取父Bean
StringgetParentName();
设置Bean的类名称,将来是要通过反射来生成实例的
voidsetBeanClassName(StringbeanClassName);
获取Bean的类名称
StringgetBeanClassName();
设置bean的scope
voidsetScope(Stringscope);
StringgetScope();
设置是否懒加载
voidsetLazyInit(booleanlazyInit);
booleanisLazyInit();
设置该Bean依赖的所有的Bean,注意,这里的依赖不是指属性依赖(如Autowire标记的),
是dependson属性设置的值。
voidsetDependsOn(String。。。dependsOn);
返回该Bean的所有依赖
String〔〕getDependsOn();
设置该Bean是否可以注入到其他Bean中,只对根据类型注入有效,
如果根据名称注入,即使这边设置了false,也是可以的
voidsetAutowireCandidate(booleanautowireCandidate);
该Bean是否可以注入到其他Bean中
booleanisAutowireCandidate();
主要的。同一接口的多个实现,如果不指定名字的话,Spring会优先选择设置primary为true的bean
voidsetPrimary(booleanprimary);
是否是primary的
booleanisPrimary();
如果该Bean采用工厂方法生成,指定工厂名称。对工厂不熟悉的读者,请参加附录
一句话就是:有些实例不是用反射生成的,而是用工厂模式生成的
voidsetFactoryBeanName(StringfactoryBeanName);
获取工厂名称
StringgetFactoryBeanName();
指定工厂类中的工厂方法名称
voidsetFactoryMethodName(StringfactoryMethodName);
获取工厂类中的工厂方法名称
StringgetFactoryMethodName();
构造器参数
ConstructorArgumentValuesgetConstructorArgumentValues();
Bean中的属性值,后面给bean注入属性值的时候会说到
MutablePropertyValuesgetPropertyValues();
是否singleton
booleanisSingleton();
是否prototype
booleanisPrototype();
如果这个Bean是被设置为abstract,那么不能实例化,
常用于作为父bean用于继承,其实也很少用。。。。。。
booleanisAbstract();
intgetRole();
StringgetDescription();
StringgetResourceDescription();
BeanDefinitiongetOriginatingBeanDefinition();
}
这个BeanDefinition其实已经包含很多的信息了,暂时不清楚所有的方法对应什么东西没关系,希望看完本文后读者可以彻底搞清楚里面的所有东西。
这里接口虽然那么多,但是没有类似getInstance()这种方法来获取我们定义的类的实例,真正的我们定义的类生成的实例到哪里去了呢?别着急,这个要很后面才能讲到。
有了BeanDefinition的概念以后,我们再往下看refreshBeanFactory()方法中的剩余部分:
java
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
虽然只有两个方法,但路还很长啊
customizeBeanFactory
customizeBeanFactory(beanFactory)比较简单,就是配置是否允许BeanDefinition覆盖、是否允许循环引用。
java
protectedvoidcustomizeBeanFactory(DefaultListableBeanFactorybeanFactory){
if(this。allowBeanDefinitionOverriding!null){
是否允许Bean定义覆盖
beanFactory。setAllowBeanDefinitionOverriding(this。allowBeanDefinitionOverriding);
}
if(this。allowCircularReferences!null){
是否允许Bean间的循环依赖
beanFactory。setAllowCircularReferences(this。allowCircularReferences);
}
}
BeanDefinition的覆盖问题可能会有开发者碰到这个坑,就是在配置文件中定义bean时使用了相同的id或name,默认情况下,allowBeanDefinitionOverriding属性为null,如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖。
循环引用也很好理解:A依赖B,而B依赖A。或A依赖B,B依赖C,而C依赖A。
默认情况下,Spring允许循环依赖,当然如果你在A的构造方法中依赖B,在B的构造方法中依赖A是不行的。
至于这两个属性怎么配置?我在附录中进行了介绍,尤其对于覆盖问题,很多人都希望禁止出现Bean覆盖,可是Spring默认是不同文件的时候可以覆盖的。
之后的源码中还会出现这两个属性,读者有个印象就可以了,它们不是非常重要。
加载Bean:loadBeanDefinitions
接下来是最重要的loadBeanDefinitions(beanFactory)方法了,这个方法将根据配置,加载各个Bean,然后放到BeanFactory中。
读取配置的操作在XmlBeanDefinitionReader中,其负责加载配置、解析。
AbstractXmlApplicationContext。java80
java
我们可以看到,此方法将通过一个XmlBeanDefinitionReader实例来加载各个Bean。
Override
protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsBeansException,IOException{
给这个BeanFactory实例化一个XmlBeanDefinitionReader
XmlBeanDefinitionReaderbeanDefinitionReadernewXmlBeanDefinitionReader(beanFactory);
Configurethebeandefinitionreaderwiththiscontexts
resourceloadingenvironment。
beanDefinitionReader。setEnvironment(this。getEnvironment());
beanDefinitionReader。setResourceLoader(this);
beanDefinitionReader。setEntityResolver(newResourceEntityResolver(this));
初始化BeanDefinitionReader,其实这个是提供给子类覆写的,
我看了一下,没有类覆写这个方法,我们姑且当做不重要吧
initBeanDefinitionReader(beanDefinitionReader);
重点来了,继续往下
loadBeanDefinitions(beanDefinitionReader);
}
现在还在这个类中,接下来用刚刚初始化的Reader开始来加载xml配置,这块代码读者可以选择性跳过,不是很重要。也就是说,下面这个代码块,读者可以很轻松地略过。
AbstractXmlApplicationContext。java120
java
protectedvoidloadBeanDefinitions(XmlBeanDefinitionReaderreader)throwsBeansException,IOException{
Resource〔〕configResourcesgetConfigResources();
if(configResources!null){
往下看
reader。loadBeanDefinitions(configResources);
}
String〔〕configLocationsgetConfigLocations();
if(configLocations!null){
2
reader。loadBeanDefinitions(configLocations);
}
}
上面虽然有两个分支,不过第二个分支很快通过解析路径转换为Resource以后也会进到这里
Override
publicintloadBeanDefinitions(Resource。。。resources)throwsBeanDefinitionStoreException{
Assert。notNull(resources,Resourcearraymustnotbenull);
intcounter0;
注意这里是个for循环,也就是每个文件是一个resource
for(Resourceresource:resources){
继续往下看
counterloadBeanDefinitions(resource);
}
最后返回counter,表示总共加载了多少的BeanDefinition
returncounter;
}
XmlBeanDefinitionReader303
Override
publicintloadBeanDefinitions(Resourceresource)throwsBeanDefinitionStoreException{
returnloadBeanDefinitions(newEncodedResource(resource));
}
XmlBeanDefinitionReader314
publicintloadBeanDefinitions(EncodedResourceencodedResource)throwsBeanDefinitionStoreException{
Assert。notNull(encodedResource,EncodedResourcemustnotbenull);
if(logger。isInfoEnabled()){
logger。info(LoadingXMLbeandefinitionsfromencodedResource。getResource());
}
用一个ThreadLocal来存放配置文件资源
SetcurrentResourcesthis。resourcesCurrentlyBeingLoaded。get();
if(currentResourcesnull){
currentResourcesnewHashSet(4);
this。resourcesCurrentlyBeingLoaded。set(currentResources);
}
if(!currentResources。add(encodedResource)){
thrownewBeanDefinitionStoreException(
DetectedcyclicloadingofencodedResourcecheckyourimportdefinitions!);
}
try{
InputStreaminputStreamencodedResource。getResource()。getInputStream();
try{
InputSourceinputSourcenewInputSource(inputStream);
if(encodedResource。getEncoding()!null){
inputSource。setEncoding(encodedResource。getEncoding());
}
核心部分是这里,往下面看
returndoLoadBeanDefinitions(inputSource,encodedResource。getResource());
}
finally{
inputStream。close();
}
}
catch(IOExceptionex){
thrownewBeanDefinitionStoreException(
IOExceptionparsingXMLdocumentfromencodedResource。getResource(),ex);
}
finally{
currentResources。remove(encodedResource);
if(currentResources。isEmpty()){
this。resourcesCurrentlyBeingLoaded。remove();
}
}
}
还在这个文件中,第388行
protectedintdoLoadBeanDefinitions(InputSourceinputSource,Resourceresource)
throwsBeanDefinitionStoreException{
try{
这里就不看了,将xml文件转换为Document对象
DocumentdocdoLoadDocument(inputSource,resource);
继续
returnregisterBeanDefinitions(doc,resource);
}
catch(。。。
}
还在这个文件中,第505行
返回值:返回从当前配置文件加载了多少数量的Bean
publicintregisterBeanDefinitions(Documentdoc,Resourceresource)throwsBeanDefinitionStoreException{
BeanDefinitionDocumentReaderdocumentReadercreateBeanDefinitionDocumentReader();
intcountBeforegetRegistry()。getBeanDefinitionCount();
这里
documentReader。registerBeanDefinitions(doc,createReaderContext(resource));
returngetRegistry()。getBeanDefinitionCount()countBefore;
}
DefaultBeanDefinitionDocumentReader90
Override
publicvoidregisterBeanDefinitions(Documentdoc,XmlReaderContextreaderContext){
this。readerContextreaderContext;
logger。debug(Loadingbeandefinitions);
Elementrootdoc。getDocumentElement();
从xml根节点开始解析文件
doRegisterBeanDefinitions(root);
}
经过漫长的链路,一个配置文件终于转换为一颗DOM树了,注意,这里指的是其中一个配置文件,不是所有的,读者可以看到上面有个for循环的。下面开始从根节点开始解析:
doRegisterBeanDefinitions:
java
DefaultBeanDefinitionDocumentReader116
protectedvoiddoRegisterBeanDefinitions(Elementroot){
我们看名字就知道,BeanDefinitionParserDelegate必定是一个重要的类,它负责解析Bean定义,
这里为什么要定义一个parent?看到后面就知道了,是递归问题,
因为内部是可以定义的,所以这个方法的root其实不一定就是xml的根节点,也可以是嵌套在里面的节点,从源码分析的角度,我们当做根节点就好了
BeanDefinitionParserDelegateparentthis。delegate;
this。delegatecreateDelegate(getReaderContext(),root,parent);
if(this。delegate。isDefaultNamespace(root)){
这块说的是根节点中的profile是否是当前环境需要的,
如果当前环境配置的profile不包含此profile,那就直接return了,不对此解析
不熟悉profile为何物,不熟悉怎么配置profile读者的请移步附录区
StringprofileSpecroot。getAttribute(PROFILEATTRIBUTE);
if(StringUtils。hasText(profileSpec)){
String〔〕specifiedProfilesStringUtils。tokenizeToStringArray(
profileSpec,BeanDefinitionParserDelegate。MULTIVALUEATTRIBUTEDELIMITERS);
if(!getReaderContext()。getEnvironment()。acceptsProfiles(specifiedProfiles)){
if(logger。isInfoEnabled()){
logger。info(SkippedXMLbeandefinitionfileduetospecifiedprofiles〔profileSpec
〕notmatching:getReaderContext()。getResource());
}
return;
}
}
}
preProcessXml(root);钩子
往下看
parseBeanDefinitions(root,this。delegate);
postProcessXml(root);钩子
this。delegateparent;
}
preProcessXml(root)和postProcessXml(root)是给子类用的钩子方法,鉴于没有被使用到,也不是我们的重点,我们直接跳过。
这里涉及到了profile的问题,对于不了解的读者,我在附录中对profile做了简单的解释,读者可以参考一下。
接下来,看核心解析方法parseBeanDefinitions(root,this。delegate):
java
defaultnamespace涉及到的就四个标签、、和,
其他的属于custom的
protectedvoidparseBeanDefinitions(Elementroot,BeanDefinitionParserDelegatedelegate){
if(delegate。isDefaultNamespace(root)){
NodeListnlroot。getChildNodes();
for(inti0;inl。getLength();i){
Nodenodenl。item(i);
if(nodeinstanceofElement){
Elementele(Element)node;
if(delegate。isDefaultNamespace(ele)){
解析defaultnamespace下面的几个元素
parseDefaultElement(ele,delegate);
}
else{
解析其他namespace的元素
delegate。parseCustomElement(ele);
}
}
}
}
else{
delegate。parseCustomElement(root);
}
}
从上面的代码,我们可以看到,对于每个配置来说,分别进入到parseDefaultElement(ele,delegate);和delegate。parseCustomElement(ele);这两个分支了。
parseDefaultElement(ele,delegate)代表解析的节点是、、、这几个。
这里的四个标签之所以是default的,是因为它们是处于这个namespace下定义的:
http:www。springframework。orgschemabeans
又到初学者科普时间,不熟悉namespace的读者请看下面贴出来的xml,这里的第二行xmlns就是咯。
xml
beansxmlns:xsihttp:www。w3。org2001XMLSchemainstance
xmlnshttp:www。springframework。orgschemabeans
xsi:schemaLocation
http:www。springframework。orgschemabeans
http:www。springframework。orgschemabeansspringbeans。xsd
defaultautowirebyName
而对于其他的标签,将进入到delegate。parseCustomElement(element)这个分支。如我们经常会使用到的、、、等。
这些属于扩展,如果需要使用上面这些非default标签,那么上面的xml头部的地方也要引入相应的namespace和。xsd文件的路径,如下所示。同时代码中需要提供相应的parser来解析,如MvcNamespaceHandler、TaskNamespaceHandler、ContextNamespaceHandler、AopNamespaceHandler等。
假如读者想分析的实现原理,就应该到ContextNamespaceHandler中找答案。
xml
beansxmlns:xsihttp:www。w3。org2001XMLSchemainstance
xmlnshttp:www。springframework。orgschemabeans
xmlns:contexthttp:www。springframework。orgschemacontext
xmlns:mvchttp:www。springframework。orgschemamvc
xsi:schemaLocation
http:www。springframework。orgschemabeans
http:www。springframework。orgschemabeansspringbeans。xsd
http:www。springframework。orgschemacontext
http:www。springframework。orgschemacontextspringcontext。xsd
http:www。springframework。orgschemamvc
http:www。springframework。orgschemamvcspringmvc。xsd
defaultautowirebyName
同理,以后你要是碰到这种标签,那么就应该搜一搜是不是有DubboNamespaceHandler这个处理类。
回过神来,看看处理default标签的方法:
java
privatevoidparseDefaultElement(Elementele,BeanDefinitionParserDelegatedelegate){
if(delegate。nodeNameEquals(ele,IMPORTELEMENT)){
处理标签
importBeanDefinitionResource(ele);
}
elseif(delegate。nodeNameEquals(ele,ALIASELEMENT)){
处理标签定义
processAliasRegistration(ele);
}
elseif(delegate。nodeNameEquals(ele,BEANELEMENT)){
处理标签定义,这也算是我们的重点吧
processBeanDefinition(ele,delegate);
}
elseif(delegate。nodeNameEquals(ele,NESTEDBEANSELEMENT)){
如果碰到的是嵌套的标签,需要递归
doRegisterBeanDefinitions(ele);
}
}
如果每个标签都说,那我不吐血,你们都要吐血了。我们挑我们的重点标签出来说。
processBeanDefinition解析bean标签
下面是processBeanDefinition解析标签:
DefaultBeanDefinitionDocumentReader298
java
protectedvoidprocessBeanDefinition(Elementele,BeanDefinitionParserDelegatedelegate){
将节点中的信息提取出来,然后封装到一个BeanDefinitionHolder中,细节往下看
BeanDefinitionHolderbdHolderdelegate。parseBeanDefinitionElement(ele);
下面的几行先不要看,跳过先,跳过先,跳过先,后面会继续说的
if(bdHolder!null){
bdHolderdelegate。decorateBeanDefinitionIfRequired(ele,bdHolder);
try{
Registerthefinaldecoratedinstance。
BeanDefinitionReaderUtils。registerBeanDefinition(bdHolder,getReaderContext()。getRegistry());
}
catch(BeanDefinitionStoreExceptionex){
getReaderContext()。error(Failedtoregisterbeandefinitionwithname
bdHolder。getBeanName(),ele,ex);
}
Sendregistrationevent。
getReaderContext()。fireComponentRegistered(newBeanComponentDefinition(bdHolder));
}
}
继续往下看怎么解析之前,我们先看下标签中可以定义哪些属性:
Property
class类的全限定名
name可指定id、name(用逗号、分号、空格分隔)
scope作用域
constructorarguments指定构造参数
properties设置属性的值
autowiringmodeno(默认值)、byName、byType、constructor
lazyinitializationmode是否懒加载(如果被非懒加载的bean依赖了那么其实也就不能懒加载了)
initializationmethodbean属性设置完成后,会调用这个方法
destructionmethodbean销毁后的回调方法
上面表格中的内容我想大家都非常熟悉吧,如果不熟悉,那就是你不够了解Spring的配置了。
简单地说就是像下面这样子:
xml
beanidexampleBeannamename1,name2,name3classcom。javadoop。ExampleBean
scopesingletonlazyinittrueinitmethodinitdestroymethodcleanup
property
bean
当然,除了上面举例出来的这些,还有factorybean、factorymethod、、、、这几个,大家是不是熟悉呢?自己检验一下自己对Spring中bean的了解程度。
有了以上这些知识以后,我们再继续往里看怎么解析bean元素,是怎么转换到BeanDefinitionHolder的。
BeanDefinitionParserDelegate428
java
publicBeanDefinitionHolderparseBeanDefinitionElement(Elementele){
returnparseBeanDefinitionElement(ele,null);
}
publicBeanDefinitionHolderparseBeanDefinitionElement(Elementele,BeanDefinitioncontainingBean){
Stringidele。getAttribute(IDATTRIBUTE);
StringnameAttrele。getAttribute(NAMEATTRIBUTE);
ListaliasesnewArrayList();
将name属性的定义按照逗号、分号、空格切分,形成一个别名列表数组,
当然,如果你不定义name属性的话,就是空的了
我在附录中简单介绍了一下id和name的配置,大家可以看一眼,有个20秒就可以了
if(StringUtils。hasLength(nameAttr)){
String〔〕nameArrStringUtils。tokenizeToStringArray(nameAttr,MULTIVALUEATTRIBUTEDELIMITERS);
aliases。addAll(Arrays。asList(nameArr));
}
StringbeanNameid;
如果没有指定id,那么用别名列表的第一个名字作为beanName
if(!StringUtils。hasText(beanName)!aliases。isEmpty()){
beanNamealiases。remove(0);
if(logger。isDebugEnabled()){
logger。debug(NoXMLidspecifiedusingbeanName
asbeannameandaliasesasaliases);
}
}
if(containingBeannull){
checkNameUniqueness(beanName,aliases,ele);
}
根据。。。中的配置创建BeanDefinition,然后把配置中的信息都设置到实例中,
细节后面细说,先知道下面这行结束后,一个BeanDefinition实例就出来了。
AbstractBeanDefinitionbeanDefinitionparseBeanDefinitionElement(ele,beanName,containingBean);
到这里,整个标签就算解析结束了,一个BeanDefinition就形成了。
if(beanDefinition!null){
如果都没有设置id和name,那么此时的beanName就会为null,进入下面这块代码产生
如果读者不感兴趣的话,我觉得不需要关心这块代码,对本文源码分析来说,这些东西不重要
if(!StringUtils。hasText(beanName)){
try{
if(containingBean!null){按照我们的思路,这里containingBean是null的
beanNameBeanDefinitionReaderUtils。generateBeanName(
beanDefinition,this。readerContext。getRegistry(),true);
}
else{
如果我们不定义id和name,那么我们引言里的那个例子:
1。beanName为:com。javadoop。example。MessageServiceImpl0
2。beanClassName为:com。javadoop。example。MessageServiceImpl
beanNamethis。readerContext。generateBeanName(beanDefinition);
StringbeanClassNamebeanDefinition。getBeanClassName();
if(beanClassName!null
beanName。startsWith(beanClassName)beanName。length()beanClassName。length()
!this。readerContext。getRegistry()。isBeanNameInUse(beanClassName)){
把beanClassName设置为Bean的别名
aliases。add(beanClassName);
}
}
if(logger。isDebugEnabled()){
logger。debug(NeitherXMLidnornamespecified
usinggeneratedbeanname〔beanName〕);
}
}
catch(Exceptionex){
error(ex。getMessage(),ele);
returnnull;
}
}
String〔〕aliasesArrayStringUtils。toStringArray(aliases);
返回BeanDefinitionHolder
returnnewBeanDefinitionHolder(beanDefinition,beanName,aliasesArray);
}
returnnull;
}
然后,我们再看看怎么根据配置创建BeanDefinition实例的:
java
publicAbstractBeanDefinitionparseBeanDefinitionElement(
Elementele,StringbeanName,BeanDefinitioncontainingBean){
this。parseState。push(newBeanEntry(beanName));
StringclassNamenull;
if(ele。hasAttribute(CLASSATTRIBUTE)){
classNameele。getAttribute(CLASSATTRIBUTE)。trim();
}
try{
Stringparentnull;
if(ele。hasAttribute(PARENTATTRIBUTE)){
parentele。getAttribute(PARENTATTRIBUTE);
}
创建BeanDefinition,然后设置类信息而已,很简单,就不贴代码了
AbstractBeanDefinitionbdcreateBeanDefinition(className,parent);
设置BeanDefinition的一堆属性,这些属性定义在AbstractBeanDefinition中
parseBeanDefinitionAttributes(ele,beanName,containingBean,bd);
bd。setDescription(DomUtils。getChildElementValueByTagName(ele,DESCRIPTIONELEMENT));
下面的一堆是解析。。。。。。内部的子元素,
解析出来以后的信息都放到bd的属性中
解析
parseMetaElements(ele,bd);
解析
parseLookupOverrideSubElements(ele,bd。getMethodOverrides());
解析
parseReplacedMethodSubElements(ele,bd。getMethodOverrides());
解析
parseConstructorArgElements(ele,bd);
解析
parsePropertyElements(ele,bd);
解析
parseQualifierElements(ele,bd);
bd。setResource(this。readerContext。getResource());
bd。setSource(extractSource(ele));
returnbd;
}
catch(ClassNotFoundExceptionex){
error(Beanclass〔className〕notfound,ele,ex);
}
catch(NoClassDefFoundErrorerr){
error(Classthatbeanclass〔className〕dependsonnotfound,ele,err);
}
catch(Throwableex){
error(Unexpectedfailureduringbeandefinitionparsing,ele,ex);
}
finally{
this。parseState。pop();
}
returnnull;
}
到这里,我们已经完成了根据配置创建了一个BeanDefinitionHolder实例。注意,是一个。
我们回到解析的入口方法:
java
protectedvoidprocessBeanDefinition(Elementele,BeanDefinitionParserDelegatedelegate){
将节点转换为BeanDefinitionHolder,就是上面说的一堆
BeanDefinitionHolderbdHolderdelegate。parseBeanDefinitionElement(ele);
if(bdHolder!null){
如果有自定义属性的话,进行相应的解析,先忽略
bdHolderdelegate。decorateBeanDefinitionIfRequired(ele,bdHolder);
try{
我们把这步叫做注册Bean吧
BeanDefinitionReaderUtils。registerBeanDefinition(bdHolder,getReaderContext()。getRegistry());
}
catch(BeanDefinitionStoreExceptionex){
getReaderContext()。error(Failedtoregisterbeandefinitionwithname
bdHolder。getBeanName(),ele,ex);
}
注册完成后,发送事件,本文不展开说这个
getReaderContext()。fireComponentRegistered(newBeanComponentDefinition(bdHolder));
}
}
大家再仔细看一下这块吧,我们后面就不回来说这个了。这里已经根据一个标签产生了一个BeanDefinitionHolder的实例,这个实例里面也就是一个BeanDefinition的实例和它的beanName、aliases这三个信息,注意,我们的关注点始终在BeanDefinition上:
java
publicclassBeanDefinitionHolderimplementsBeanMetadataElement{
privatefinalBeanDefinitionbeanDefinition;
privatefinalStringbeanName;
privatefinalString〔〕aliases;
。。。
然后我们准备注册这个BeanDefinition,最后,把这个注册事件发送出去。
下面,我们开始说说注册Bean吧。
注册Bean
BeanDefinitionReaderUtils143
java
publicstaticvoidregisterBeanDefinition(
BeanDefinitionHolderdefinitionHolder,BeanDefinitionRegistryregistry)
throwsBeanDefinitionStoreException{
StringbeanNamedefinitionHolder。getBeanName();
注册这个Bean
registry。registerBeanDefinition(beanName,definitionHolder。getBeanDefinition());
如果还有别名的话,也要根据别名全部注册一遍,不然根据别名就会找不到Bean了
String〔〕aliasesdefinitionHolder。getAliases();
if(aliases!null){
for(Stringalias:aliases){
aliasbeanName保存它们的别名信息,这个很简单,用一个map保存一下就可以了,
获取的时候,会先将alias转换为beanName,然后再查找
registry。registerAlias(beanName,alias);
}
}
}
别名注册的放一边,毕竟它很简单,我们看看怎么注册Bean。
DefaultListableBeanFactory793
java
Override
publicvoidregisterBeanDefinition(StringbeanName,BeanDefinitionbeanDefinition)
throwsBeanDefinitionStoreException{
Assert。hasText(beanName,Beannamemustnotbeempty);
Assert。notNull(beanDefinition,BeanDefinitionmustnotbenull);
if(beanDefinitioninstanceofAbstractBeanDefinition){
try{
((AbstractBeanDefinition)beanDefinition)。validate();
}
catch(BeanDefinitionValidationExceptionex){
thrownewBeanDefinitionStoreException(。。。);
}
}
old?还记得允许bean覆盖这个配置吗?allowBeanDefinitionOverriding
BeanDefinitionoldBeanDefinition;
之后会看到,所有的Bean注册后会放入这个beanDefinitionMap中
oldBeanDefinitionthis。beanDefinitionMap。get(beanName);
处理重复名称的Bean定义的情况
if(oldBeanDefinition!null){
if(!isAllowBeanDefinitionOverriding()){
如果不允许覆盖的话,抛异常
thrownewBeanDefinitionStoreException(beanDefinition。getResourceDescription()。。。
}
elseif(oldBeanDefinition。getRole()beanDefinition。getRole()){
log。。。用框架定义的Bean覆盖用户自定义的Bean
}
elseif(!beanDefinition。equals(oldBeanDefinition)){
log。。。用新的Bean覆盖旧的Bean
}
else{
log。。。用同等的Bean覆盖旧的Bean,这里指的是equals方法返回true的Bean
}
覆盖
this。beanDefinitionMap。put(beanName,beanDefinition);
}
else{
判断是否已经有其他的Bean开始初始化了。
注意,注册Bean这个动作结束,Bean依然还没有初始化,我们后面会有大篇幅说初始化过程,
在Spring容器启动的最后,会预初始化所有的singletonbeans
if(hasBeanCreationStarted()){
Cannotmodifystartuptimecollectionelementsanymore(forstableiteration)
synchronized(this。beanDefinitionMap){
this。beanDefinitionMap。put(beanName,beanDefinition);
ListupdatedDefinitionsnewArrayList(this。beanDefinitionNames。size()1);
updatedDefinitions。addAll(this。beanDefinitionNames);
updatedDefinitions。add(beanName);
this。beanDefinitionNamesupdatedDefinitions;
if(this。manualSingletonNames。contains(beanName)){
SetupdatedSingletonsnewLinkedHashSet(this。manualSingletonNames);
updatedSingletons。remove(beanName);
this。manualSingletonNamesupdatedSingletons;
}
}
}
else{
最正常的应该是进到这个分支。
将BeanDefinition放到这个map中,这个map保存了所有的BeanDefinition
this。beanDefinitionMap。put(beanName,beanDefinition);
这是个ArrayList,所以会按照bean配置的顺序保存每一个注册的Bean的名字
this。beanDefinitionNames。add(beanName);
这是个LinkedHashSet,代表的是手动注册的singletonbean,
注意这里是remove方法,到这里的Bean当然不是手动注册的
手动指的是通过调用以下方法注册的bean:
registerSingleton(StringbeanName,ObjectsingletonObject)
这不是重点,解释只是为了不让大家疑惑。Spring会在后面手动注册一些Bean,
如environment、systemProperties等bean,我们自己也可以在运行时注册Bean到容器中的
this。manualSingletonNames。remove(beanName);
}
这个不重要,在预初始化的时候会用到,不必管它。
this。frozenBeanDefinitionNamesnull;
}
if(oldBeanDefinition!nullcontainsSingleton(beanName)){
resetBeanDefinition(beanName);
}
}
总结一下,到这里已经初始化了Bean容器,配置也相应的转换为了一个个BeanDefinition,然后注册了各个BeanDefinition到注册中心,并且发送了注册事件。
分割线
到这里是一个分水岭,前面的内容都还算比较简单,不过应该也比较繁琐,大家要清楚地知道前面都做了哪些事情。
Bean容器实例化完成后
说到这里,我们回到refresh()方法,我重新贴了一遍代码,看看我们说到哪了。是的,我们才说完obtainFreshBeanFactory()方法。
考虑到篇幅,这里开始大幅缩减掉没必要详细介绍的部分,大家直接看下面的代码中的注释就好了。
java
Override
publicvoidrefresh()throwsBeansException,IllegalStateException{
来个锁,不然refresh()还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized(this。startupShutdownMonitor){
准备工作,记录下容器的启动时间、标记已启动状态、处理配置文件中的占位符
prepareRefresh();
这步比较关键,这步完成后,配置文件就会解析成一个个Bean定义,注册到BeanFactory中,
当然,这里说的Bean还没有初始化,只是配置信息都提取出来了,
注册也只是将这些信息都保存到了注册中心(说到底核心是一个beanNamebeanDefinition的map)
ConfigurableListableBeanFactorybeanFactoryobtainFreshBeanFactory();
设置BeanFactory的类加载器,添加几个BeanPostProcessor,手动注册几个特殊的bean
这块待会会展开说
prepareBeanFactory(beanFactory);
try{
【这里需要知道BeanFactoryPostProcessor这个知识点,Bean如果实现了此接口,
那么在容器初始化以后,Spring会负责调用里面的postProcessBeanFactory方法。】
这里是提供给子类的扩展点,到这里的时候,所有的Bean都加载、注册完成了,但是都还没有初始化
具体的子类可以在这步的时候添加一些特殊的BeanFactoryPostProcessor的实现类或做点什么事
postProcessBeanFactory(beanFactory);
调用BeanFactoryPostProcessor各个实现类的postProcessBeanFactory(factory)回调方法
invokeBeanFactoryPostProcessors(beanFactory);
注册BeanPostProcessor的实现类,注意看和BeanFactoryPostProcessor的区别
此接口两个方法:postProcessBeforeInitialization和postProcessAfterInitialization
两个方法分别在Bean初始化之前和初始化之后得到执行。这里仅仅是注册,之后会看到回调这两方法的时机
registerBeanPostProcessors(beanFactory);
初始化当前ApplicationContext的MessageSource,国际化这里就不展开说了,不然没完没了了
initMessageSource();
初始化当前ApplicationContext的事件广播器,这里也不展开了
initApplicationEventMulticaster();
从方法名就可以知道,典型的模板方法(钩子方法),不展开说
具体的子类可以在这里初始化一些特殊的Bean(在初始化singletonbeans之前)
onRefresh();
注册事件监听器,监听器需要实现ApplicationListener接口。这也不是我们的重点,过
registerListeners();
重点,重点,重点
初始化所有的singletonbeans
(lazyinit的除外)
finishBeanFactoryInitialization(beanFactory);
最后,广播事件,ApplicationContext初始化完成,不展开
finishRefresh();
}
catch(BeansExceptionex){
if(logger。isWarnEnabled()){
logger。warn(Exceptionencounteredduringcontextinitialization
cancellingrefreshattempt:ex);
}
Destroyalreadycreatedsingletonstoavoiddanglingresources。
销毁已经初始化的singleton的Beans,以免有些bean会一直占用资源
destroyBeans();
Resetactiveflag。
cancelRefresh(ex);
把异常往外抛
throwex;
}
finally{
ResetcommonintrospectioncachesinSpringscore,sincewe
mightnoteverneedmetadataforsingletonbeansanymore。。。
resetCommonCaches();
}
}
}
准备Bean容器:prepareBeanFactory
之前我们说过,Spring把我们在xml配置的bean都注册以后,会手动注册一些特殊的bean。
这里简单介绍下prepareBeanFactory(factory)方法:
java
Configurethefactorysstandardcontextcharacteristics,
suchasthecontextsClassLoaderandpostprocessors。
parambeanFactorytheBeanFactorytoconfigure
protectedvoidprepareBeanFactory(ConfigurableListableBeanFactorybeanFactory){
设置BeanFactory的类加载器,我们知道BeanFactory需要加载类,也就需要类加载器,
这里设置为加载当前ApplicationContext类的类加载器
beanFactory。setBeanClassLoader(getClassLoader());
设置BeanExpressionResolver
beanFactory。setBeanExpressionResolver(newStandardBeanExpressionResolver(beanFactory。getBeanClassLoader()));
beanFactory。addPropertyEditorRegistrar(newResourceEditorRegistrar(this,getEnvironment()));
添加一个BeanPostProcessor,这个processor比较简单:
实现了Aware接口的beans在初始化的时候,这个processor负责回调,
这个我们很常用,如我们会为了获取ApplicationContext而implementApplicationContextAware
注意:它不仅仅回调ApplicationContextAware,
还会负责回调EnvironmentAware、ResourceLoaderAware等,看下源码就清楚了
beanFactory。addBeanPostProcessor(newApplicationContextAwareProcessor(this));
下面几行的意思就是,如果某个bean依赖于以下几个接口的实现类,在自动装配的时候忽略它们,
Spring会通过其他方式来处理这些依赖。
beanFactory。ignoreDependencyInterface(EnvironmentAware。class);
beanFactory。ignoreDependencyInterface(EmbeddedValueResolverAware。class);
beanFactory。ignoreDependencyInterface(ResourceLoaderAware。class);
beanFactory。ignoreDependencyInterface(ApplicationEventPublisherAware。class);
beanFactory。ignoreDependencyInterface(MessageSourceAware。class);
beanFactory。ignoreDependencyInterface(ApplicationContextAware。class);
下面几行就是为特殊的几个bean赋值,如果有bean依赖了以下几个,会注入这边相应的值,
之前我们说过,当前ApplicationContext持有一个BeanFactory,这里解释了第一行。
ApplicationContext还继承了ResourceLoader、ApplicationEventPublisher、MessageSource
所以对于这几个依赖,可以赋值为this,注意this是一个ApplicationContext
那这里怎么没看到为MessageSource赋值呢?那是因为MessageSource被注册成为了一个普通的bean
beanFactory。registerResolvableDependency(BeanFactory。class,beanFactory);
beanFactory。registerResolvableDependency(ResourceLoader。class,this);
beanFactory。registerResolvableDependency(ApplicationEventPublisher。class,this);
beanFactory。registerResolvableDependency(ApplicationContext。class,this);
这个BeanPostProcessor也很简单,在bean实例化后,如果是ApplicationListener的子类,
那么将其添加到listener列表中,可以理解成:注册事件监听器
beanFactory。addBeanPostProcessor(newApplicationListenerDetector(this));
这里涉及到特殊的bean,名为:loadTimeWeaver,这不是我们的重点,忽略它
tips:ltw是AspectJ的概念,指的是在运行期进行织入,这个和SpringAOP不一样,
感兴趣的读者请参考我写的关于AspectJ的另一篇文章https:www。javadoop。compostaspectj
if(beanFactory。containsBean(LOADTIMEWEAVERBEANNAME)){
beanFactory。addBeanPostProcessor(newLoadTimeWeaverAwareProcessor(beanFactory));
SetatemporaryClassLoaderfortypematching。
beanFactory。setTempClassLoader(newContextTypeMatchClassLoader(beanFactory。getBeanClassLoader()));
}
从下面几行代码我们可以知道,Spring往往很智能就是因为它会帮我们默认注册一些有用的bean,
我们也可以选择覆盖
如果没有定义environment这个bean,那么Spring会手动注册一个
if(!beanFactory。containsLocalBean(ENVIRONMENTBEANNAME)){
beanFactory。registerSingleton(ENVIRONMENTBEANNAME,getEnvironment());
}
如果没有定义systemProperties这个bean,那么Spring会手动注册一个
if(!beanFactory。containsLocalBean(SYSTEMPROPERTIESBEANNAME)){
beanFactory。registerSingleton(SYSTEMPROPERTIESBEANNAME,getEnvironment()。getSystemProperties());
}
如果没有定义systemEnvironment这个bean,那么Spring会手动注册一个
if(!beanFactory。containsLocalBean(SYSTEMENVIRONMENTBEANNAME)){
beanFactory。registerSingleton(SYSTEMENVIRONMENTBEANNAME,getEnvironment()。getSystemEnvironment());
}
}
在上面这块代码中,Spring对一些特殊的bean进行了处理,读者如果暂时还不能消化它们也没有关系,慢慢往下看。
初始化所有的singletonbeans
我们的重点当然是finishBeanFactoryInitialization(beanFactory);这个巨头了,这里会负责初始化所有的singletonbeans。
注意,后面的描述中,我都会使用初始化或预初始化来代表这个阶段,Spring会在这个阶段完成所有的singletonbeans的实例化。
我们来总结一下,到目前为止,应该说BeanFactory已经创建完成,并且所有的实现了BeanFactoryPostProcessor接口的Bean都已经初始化并且其中的postProcessBeanFactory(factory)方法已经得到回调执行了。而且Spring已经手动注册了一些特殊的Bean,如environment、systemProperties等。
剩下的就是初始化singletonbeans了,我们知道它们是单例的,如果没有设置懒加载,那么Spring会在接下来初始化所有的singletonbeans。
AbstractApplicationContext。java834
java
初始化剩余的singletonbeans
protectedvoidfinishBeanFactoryInitialization(ConfigurableListableBeanFactorybeanFactory){
首先,初始化名字为conversionService的Bean。本着送佛送到西的精神,我在附录中简单介绍了一下ConversionService,因为这实在太实用了
什么,看代码这里没有初始化Bean啊!
注意了,初始化的动作包装在beanFactory。getBean(。。。)中,这里先不说细节,先往下看吧
if(beanFactory。containsBean(CONVERSIONSERVICEBEANNAME)
beanFactory。isTypeMatch(CONVERSIONSERVICEBEANNAME,ConversionService。class)){
beanFactory。setConversionService(
beanFactory。getBean(CONVERSIONSERVICEBEANNAME,ConversionService。class));
}
Registeradefaultembeddedvalueresolverifnobeanpostprocessor
(suchasaPropertyPlaceholderConfigurerbean)registeredanybefore:
atthispoint,primarilyforresolutioninannotationattributevalues。
if(!beanFactory。hasEmbeddedValueResolver()){
beanFactory。addEmbeddedValueResolver(newStringValueResolver(){
Override
publicStringresolveStringValue(StringstrVal){
returngetEnvironment()。resolvePlaceholders(strVal);
}
});
}
先初始化LoadTimeWeaverAware类型的Bean
之前也说过,这是AspectJ相关的内容,放心跳过吧
String〔〕weaverAwareNamesbeanFactory。getBeanNamesForType(LoadTimeWeaverAware。class,false,false);
for(StringweaverAwareName:weaverAwareNames){
getBean(weaverAwareName);
}
StopusingthetemporaryClassLoaderfortypematching。
beanFactory。setTempClassLoader(null);
没什么别的目的,因为到这一步的时候,Spring已经开始预初始化singletonbeans了,
肯定不希望这个时候还出现bean定义解析、加载、注册。
beanFactory。freezeConfiguration();
开始初始化
beanFactory。preInstantiateSingletons();
}
从上面最后一行往里看,我们就又回到DefaultListableBeanFactory这个类了,这个类大家应该都不陌生了吧。
preInstantiateSingletons
DefaultListableBeanFactory728
java
Override
publicvoidpreInstantiateSingletons()throwsBeansException{
if(this。logger。isDebugEnabled()){
this。logger。debug(Preinstantiatingsingletonsinthis);
}
this。beanDefinitionNames保存了所有的beanNames
ListbeanNamesnewArrayList(this。beanDefinitionNames);
下面这个循环,触发所有的非懒加载的singletonbeans的初始化操作
for(StringbeanName:beanNames){
合并父Bean中的配置,注意中的parent,用的不多吧,
考虑到这可能会影响大家的理解,我在附录中解释了一下Bean继承,不了解的请到附录中看一下
RootBeanDefinitionbdgetMergedLocalBeanDefinition(beanName);
非抽象、非懒加载的singletons。如果配置了abstracttrue,那是不需要初始化的
if(!bd。isAbstract()bd。isSingleton()!bd。isLazyInit()){
处理FactoryBean(读者如果不熟悉FactoryBean,请移步附录区了解)
if(isFactoryBean(beanName)){
FactoryBean的话,在beanName前面加上‘’符号。再调用getBean,getBean方法别急
finalFactoryBeanlt;?factory(FactoryBeanlt;?)getBean(FACTORYBEANPREFIXbeanName);
判断当前FactoryBean是否是SmartFactoryBean的实现,此处忽略,直接跳过
booleanisEagerInit;
if(System。getSecurityManager()!nullfactoryinstanceofSmartFactoryBean){
isEagerInitAccessController。doPrivileged(newPrivilegedAction(){
Override
publicBooleanrun(){
return((SmartFactoryBeanlt;?)factory)。isEagerInit();
}
},getAccessControlContext());
}
else{
isEagerInit(factoryinstanceofSmartFactoryBean
((SmartFactoryBeanlt;?)factory)。isEagerInit());
}
if(isEagerInit){
getBean(beanName);
}
}
else{
对于普通的Bean,只要调用getBean(beanName)这个方法就可以进行初始化了
getBean(beanName);
}
}
}
到这里说明所有的非懒加载的singletonbeans已经完成了初始化
如果我们定义的bean是实现了SmartInitializingSingleton接口的,那么在这里得到回调,忽略
for(StringbeanName:beanNames){
ObjectsingletonInstancegetSingleton(beanName);
if(singletonInstanceinstanceofSmartInitializingSingleton){
finalSmartInitializingSingletonsmartSingleton(SmartInitializingSingleton)singletonInstance;
if(System。getSecurityManager()!null){
AccessController。doPrivileged(newPrivilegedAction(){
Override
publicObjectrun(){
smartSingleton。afterSingletonsInstantiated();
returnnull;
}
},getAccessControlContext());
}
else{
smartSingleton。afterSingletonsInstantiated();
}
}
}
}
接下来,我们就进入到getBean(beanName)方法了,这个方法我们经常用来从BeanFactory中获取一个Bean,而初始化的过程也封装到了这个方法里。
getBean
在继续前进之前,读者应该具备FactoryBean的知识,如果读者还不熟悉,请移步附录部分了解FactoryBean。
AbstractBeanFactory196
java
Override
publicObjectgetBean(Stringname)throwsBeansException{
returndoGetBean(name,null,null,false);
}
我们在剖析初始化Bean的过程,但是getBean方法我们经常是用来从容器中获取Bean用的,注意切换思路,
已经初始化过了就从容器中直接返回,否则就先初始化再返回
SuppressWarnings(unchecked)
protectedTdoGetBean(
finalStringname,finalClassrequiredType,finalObject〔〕args,booleantypeCheckOnly)
throwsBeansException{
获取一个正统的beanName,处理两种情况,一个是前面说的FactoryBean(前面带‘’),
一个是别名问题,因为这个方法是getBean,获取Bean用的,你要是传一个别名进来,是完全可以的
finalStringbeanNametransformedBeanName(name);
注意跟着这个,这个是返回值
Objectbean;
检查下是不是已经创建过了
ObjectsharedInstancegetSingleton(beanName);
这里说下args呗,虽然看上去一点不重要。前面我们一路进来的时候都是getBean(beanName),
所以args传参其实是null的,但是如果args不为空的时候,那么意味着调用方不是希望获取Bean,而是创建Bean
if(sharedInstance!nullargsnull){
if(logger。isDebugEnabled()){
if(isSingletonCurrentlyInCreation(beanName)){
logger。debug(。。。);
}
else{
logger。debug(ReturningcachedinstanceofsingletonbeanbeanName);
}
}
下面这个方法:如果是普通Bean的话,直接返回sharedInstance,
如果是FactoryBean的话,返回它创建的那个实例对象
(FactoryBean知识,读者若不清楚请移步附录)
beangetObjectForBeanInstance(sharedInstance,name,beanName,null);
}
else{
if(isPrototypeCurrentlyInCreation(beanName)){
创建过了此beanName的prototype类型的bean,那么抛异常,
往往是因为陷入了循环引用
thrownewBeanCurrentlyInCreationException(beanName);
}
检查一下这个BeanDefinition在容器中是否存在
BeanFactoryparentBeanFactorygetParentBeanFactory();
if(parentBeanFactory!null!containsBeanDefinition(beanName)){
如果当前容器不存在这个BeanDefinition,试试父容器中有没有
StringnameToLookuporiginalBeanName(name);
if(args!null){
返回父容器的查询结果
return(T)parentBeanFactory。getBean(nameToLookup,args);
}
else{
NoargsdelegatetostandardgetBeanmethod。
returnparentBeanFactory。getBean(nameToLookup,requiredType);
}
}
if(!typeCheckOnly){
typeCheckOnly为false,将当前beanName放入一个alreadyCreated的Set集合中。
markBeanAsCreated(beanName);
}
稍稍总结一下:
到这里的话,要准备创建Bean了,对于singleton的Bean来说,容器中还没创建过此Bean;
对于prototype的Bean来说,本来就是要创建一个新的Bean。
try{
finalRootBeanDefinitionmbdgetMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd,beanName,args);
先初始化依赖的所有Bean,这个很好理解。
注意,这里的依赖指的是dependson中定义的依赖
String〔〕dependsOnmbd。getDependsOn();
if(dependsOn!null){
for(Stringdep:dependsOn){
检查是不是有循环依赖,这里的循环依赖和我们前面说的循环依赖又不一样,这里肯定是不允许出现的,不然要乱套了,读者想一下就知道了
if(isDependent(beanName,dep)){
thrownewBeanCreationException(mbd。getResourceDescription(),beanName,
CirculardependsonrelationshipbetweenbeanNameanddep);
}
注册一下依赖关系
registerDependentBean(dep,beanName);
先初始化被依赖项
getBean(dep);
}
}
如果是singletonscope的,创建singleton的实例
if(mbd。isSingleton()){
sharedInstancegetSingleton(beanName,newObjectFactory(){
Override
publicObjectgetObject()throwsBeansException{
try{
执行创建Bean,详情后面再说
returncreateBean(beanName,mbd,args);
}
catch(BeansExceptionex){
destroySingleton(beanName);
throwex;
}
}
});
beangetObjectForBeanInstance(sharedInstance,name,beanName,mbd);
}
如果是prototypescope的,创建prototype的实例
elseif(mbd。isPrototype()){
Itsaprototypecreateanewinstance。
ObjectprototypeInstancenull;
try{
beforePrototypeCreation(beanName);
执行创建Bean
prototypeInstancecreateBean(beanName,mbd,args);
}
finally{
afterPrototypeCreation(beanName);
}
beangetObjectForBeanInstance(prototypeInstance,name,beanName,mbd);
}
如果不是singleton和prototype的话,需要委托给相应的实现类来处理
else{
StringscopeNamembd。getScope();
finalScopescopethis。scopes。get(scopeName);
if(scopenull){
thrownewIllegalStateException(NoScoperegisteredforscopenamescopeName);
}
try{
ObjectscopedInstancescope。get(beanName,newObjectFactory(){
Override
publicObjectgetObject()throwsBeansException{
beforePrototypeCreation(beanName);
try{
执行创建Bean
returncreateBean(beanName,mbd,args);
}
finally{
afterPrototypeCreation(beanName);
}
}
});
beangetObjectForBeanInstance(scopedInstance,name,beanName,mbd);
}
catch(IllegalStateExceptionex){
thrownewBeanCreationException(beanName,
ScopescopeNameisnotactiveforthecurrentthread;consider
definingascopedproxyforthisbeanifyouintendtorefertoitfromasingleton,
ex);
}
}
}
catch(BeansExceptionex){
cleanupAfterBeanCreationFailure(beanName);
throwex;
}
}
最后,检查一下类型对不对,不对的话就抛异常,对的话就返回了
if(requiredType!nullbean!null!requiredType。isInstance(bean)){
try{
returngetTypeConverter()。convertIfNecessary(bean,requiredType);
}
catch(TypeMismatchExceptionex){
if(logger。isDebugEnabled()){
logger。debug(Failedtoconvertbeannametorequiredtype
ClassUtils。getQualifiedName(requiredType),ex);
}
thrownewBeanNotOfRequiredTypeException(name,requiredType,bean。getClass());
}
}
return(T)bean;
}
大家应该也猜到了,接下来当然是分析createBean方法:
java
protectedabstractObjectcreateBean(StringbeanName,RootBeanDefinitionmbd,Object〔〕args)throwsBeanCreationException;
第三个参数args数组代表创建实例需要的参数,不就是给构造方法用的参数,或者是工厂Bean的参数嘛,不过要注意,在我们的初始化阶段,args是null。
这回我们要到一个新的类了AbstractAutowireCapableBeanFactory,看类名,AutowireCapable?类名是不是也说明了点问题了。
主要是为了以下场景,采用Autowired注解注入属性值:
java
publicclassMessageServiceImplimplementsMessageService{
Autowired
privateUserServiceuserService;
publicStringgetMessage(){
returnuserService。getMessage();
}
}
xml
以上这种属于混用了xml和注解两种方式的配置方式,Spring会处理这种情况。
好了,读者要知道这么回事就可以了,继续向前。
AbstractAutowireCapableBeanFactory447
java
Centralmethodofthisclass:createsabeaninstance,
populatesthebeaninstance,appliespostprocessors,etc。
seedoCreateBean
Override
protectedObjectcreateBean(StringbeanName,RootBeanDefinitionmbd,Object〔〕args)throwsBeanCreationException{
if(logger。isDebugEnabled()){
logger。debug(CreatinginstanceofbeanbeanName);
}
RootBeanDefinitionmbdToUsembd;
确保BeanDefinition中的Class被加载
Classlt;?resolvedClassresolveBeanClass(mbd,beanName);
if(resolvedClass!null!mbd。hasBeanClass()mbd。getBeanClassName()!null){
mbdToUsenewRootBeanDefinition(mbd);
mbdToUse。setBeanClass(resolvedClass);
}
准备方法覆写,这里又涉及到一个概念:MethodOverrides,它来自于bean定义中的
和,如果读者感兴趣,回到bean解析的地方看看对这两个标签的解析。
我在附录中也对这两个标签的相关知识点进行了介绍,读者可以移步去看看
try{
mbdToUse。prepareMethodOverrides();
}
catch(BeanDefinitionValidationExceptionex){
thrownewBeanDefinitionStoreException(mbdToUse。getResourceDescription(),
beanName,Validationofmethodoverridesfailed,ex);
}
try{
让InstantiationAwareBeanPostProcessor在这一步有机会返回代理,
在《SpringAOP源码分析》那篇文章中有解释,这里先跳过
ObjectbeanresolveBeforeInstantiation(beanName,mbdToUse);
if(bean!null){
returnbean;
}
}
catch(Throwableex){
thr。。。