您的位置:首页 > 编程语言 > Java开发

spring初始化

2015-12-01 15:42 423 查看
很多人看开源框架源代码的时候都不知道从哪里入手,我这里推荐一个最简单的办法,写一个最简单的应用的例子,然后根据这个应用一点一点查看在源码中的运行步骤,这样就能对框架有一个基本的了解,有了这个基本的认识,再去针对不同模块扩展开来仔细研究。

本系列主要是学习spring的源码,首先是最简单的使用例子:

我们看第一行初始化了一个ClassPathXmlApplicationContext对象,

注:也可以用FileSystemXmlApplicationContext来加载,两者的区别只是查找配置文件的起始路径不同,一个以classpath为当前路径,一个是直接用文件系统的当前路径,内部没有太大区别。

注2:web工程大家都知道我们配置了ContextLoaderListener,这里暂时不做介绍,后面会有专门的分析,起始主题流程都差不多,详情请参见:从源码看Spring在web工程中的初始化。

请看下面的构造方法,参数是spring配置文件在classpath中的全路径名:

?
可以看到里面调用了另外一个构造方法(如下),其中传递了两个默认参数refresh=true立即刷新,parent=null继承为空,并且把配置文件封装为了一个String数组,这里主要是因为spring是支持多个配置文件的

?
我们看这个构造方法的代码:

首先调用了父类的构造函数
调用setConfigLocations设置配置文件位置信息(代码如下)
判断如果refresh为true则调用refresh()方法,refresh方法在AbstractApplicationContext中

setConfigLocations代码:

很简单,主要是检验是否传入参数为空然后赋值给configLocations属性,不过其中有两个小特点可以注意一下:

并没有直接把传入参数locations直接赋值给属性,而是new了一个String数组,然后循环赋值,这里主要是出于安全考虑避免外面传入的字符串数组变化影响spring内部
可以看到赋值前有调用了一下resolvePath方法,这个方法实现了一些系统变量的替换,例如路径里可以使用${}加载系统变量值

下面看refresh刷新方法,这个刷新方法主要是从配置文件加载bean配置的过程,代码如下:

上面是一个spring初始化的基本流程框架,后面几篇将陆续对其中每一个方法进行详细的分析

上篇结束的地方简单介绍了一下refresh()方法,现在我们具体分析一下它的代码细节:

1.首先可以看到整个refresh()的代码都是同步的,对应的同步对象是startupShutdownMonitor,我们看一下startupShutdownMonitor引用的地方,可以知道,只有在refresh()和close()两个方法里用到,说明这个锁是用来同步applicationContext的刷新和销毁的。



2.同步代码块的第一行是prepareRefresh()方法,代码如下:



?
这个方法也很简单

首先设置startupDate为系统当前毫秒数,代表当前applicationContext的创建时间;
设置active为true,代表当前applicationContext是活动的,可以看到对active的赋值操作是同步的,同步对象为activeMonitor,查看active的引用点,可以看到所有对 active的操作都是同步在activeMonitor下的,在调用cancelRefresh()和doClose()两个方法的时候会把它设置为false,其中cancelRefresh()代表中止refresh,doClose()则是当前applicationContext的关闭销毁方法
最后是日志的打印,info级别,我这里要说的一点是后面直接+this,代表会调用toString方法,AbstractApplicationContext重写了toString,大概格式是displayName+startup+parent displayName

3.接着是这一行:ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(),obtainFreshBeanFactory代码如下:

?
第一行调用refreshBeanFactory(),我们先跳过这行看下面,调用了getBeanFactory()获得beanFactory对象然后返回这个对象,看getBeanFactory()的代码可以看到,是做了一个同步,然后取出当前对象里的beanFactory,同步锁是beanFactoryMonitor:

注:refreshBeanFactory()和getBeanFactory()方法在AbstractRefreshableApplicationContext类里面,关于ApplicationContext的类结构我会在另外一篇文章里做专门介绍,请看:ApplicationContext的类继承结构及框架图

?
如果beanFactory为空则会抛出异常,其实一开始beanFactory肯定是null的,beanFactory的创建就是在refreshBeanFactory()方法中,下面我们看它的代码:

?
前面3行代码首先判断是否hasBeanFactory(),如果存在则调用destroyBeans()以及closeBeanFactory():

hasBeanFactory()是在判断属性beanFactory是否为空,当然同上面一样beanFactory的操作是同步的,同步对象是beanFactoryMonitor。
destroyBeans()方法只有一行代码:getBeanFactory().destroySingletons(),调用了beanFactory对象的destroySingletons()方法来销毁所有单例bean。(后面还会用到这个方法,放到后面详细介绍)
closeBeanFactory()和上面一样,依旧是同步的情况下处理beanFactory属性,首先调用setSerializationId(null),然后把beanFactory属性设置为null。

接下来后面的代码是一个创建beanFactory的过程:

调用createBeanFactory()方法创建一个beanFactory对象:

查看方法代码可以看到创建的是一个DefaultListableBeanFactory对象,参数parent传递的方法getInternalParentBeanFactory()返回的结果,getInternalParentBeanFactory()方法的代码为:

(getParent() instanceof ConfigurableApplicationContext) ? ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent()

如果当前applicationContext对象的parent是ConfigurableApplicationContext类的实例则返回当前对象的parent的beanFactory对象,否则直接返回当前对象的parent。

将当前对象的id属性作为参数调用为beanFactory对象的setSerializationId()方法,我们这里看下这个方法的代码:

?
首先,输入参数如果不为空执行(1),否则再判断如果当前对象的属性serializationId不为空,执行(2)

(1)在serializableFactories里加入一组值:键为serializationId,值为当前对象的弱引用

(2)从serializableFactories中移除键为当前对象属性serializationId的对象,也就是以前存入的当前对象的弱引用

(3)设置属性serializationId为输入参数

customizeBeanFactory()方法的代码:

?
如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性,此属性的含义:是否允许覆盖同名称的不同定义的对象

如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性,此属性的含义:是否允许bean之间循环引用

设置beanFactory的parameterNameDiscoverer属性为一个新的LocalVariableTableParameterNameDiscoverer对象,主要用asm解析class文件

设置beanFactory的parameterNameDiscoverer属性为一个新的QualifierAnnotationAutowireCandidateResolver对象,主要用于自动装配的处理

loadBeanDefinitions()方法的代码:

?
第1行创建XmlBeanDefinitionReader对象

第2行设置beanDefinitionReader的resourceLoader属性为当前对象

第3行设置beanDefinitionReader的entityResolver属性为一个新的ResourceEntityResolver对象,输入参数resourceLoader为当前对象,这个数要是用来解析xml的

第4行设置beanDefinitionReader的validationMode以及namespaceAware,参数是当前对象的validating属性,主要用于xml校检

最后一行是做了xml配置文件的读取,就不做详细描述了,有个细节是会循环加载configResources、configLocations两个里面的文件

接着是同步操作beanFactory,把创建的beanFactory对象赋值给当前ApplicationContext的beanFactory属性

refresh()方法中在上篇obtainFreshBeanFactory()方法创建了beanfactory对象,之后的代码就开始是对beanFactory对象的一些处理,BeanFactory相关的一些内容也是spring的核心内容。

注:refresh()的代码就不再次列举了,请看spring源码中AbstractApplicationContext类。

一、首先是prepareBeanFactory(beanFactory),主要是做了一些beanFactory的初始化工作,因为这个方法比较长,我们分成4部分来看,

第1部分代码:

?
第1行设置beanFactory的classLoader为当前context的classLoader
第2行设置beanFactory的表达式语言处理器,spring3增加了表达式语言的支持,默认可以使用#{bean.xxx}的形式来调用相关属性值。
第3行为beanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具,以后再做详细分析。
第4行添加了一个处理aware相关接口的beanPostProcessor扩展,主要是使用beanPostProcessor的postProcessBeforeInitialization()前置处理方法实现aware相关接口的功能,aware接口是用来给bean注入一些资源的接口,例如实现BeanFactoryAware的Bean在初始化后,Spring容器将会注入BeanFactory的实例相应的还有ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等。
第5-8行设置了几个忽略自动装配的接口,默认只有BeanFactoryAware被忽略,其他的都要自行设置,这里设置了ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware和ApplicationContextAware。
第9-12行设置了几个自动装配的特殊规则,如果是BeanFactory类型,则注入beanFactory对象,如果是ResourceLoader、ApplicationEventPublisher、ApplicationContext类型则注入当前对象(applicationContext对象)。

第2部分代码:

?
这部分判断是否定义了名为loadTimeWeaver的bean,如果定义了则添加loadTimeWeaver功能的beanPostProcessor扩展,并且创建一个临时的classLoader来让其处理真正的bean。spring的loadTimeWeaver主要是通过 instrumentation 的动态字节码增强在装载期注入依赖。具体这部分还没有很好的理解,暂时标记一下以后再专门研究看看。

第3部分代码:

?
这部分首先判断是否定义了名为systemProperties的bean,如果没有则加载系统获取当前系统属性System.getProperties()并注册为一个单例bean。假如有AccessControlException权限异常则创建一个ReadOnlySystemAttributesMap对象,可以看到创建时重写了getSystemAttribute()方法,查看ReadOnlySystemAttributesMap的代码可以得知在调用get方法的时候会去调用这个方法来获取key对应的对象,当获取依旧有权限异常AccessControlException的时候则返回null。

第4部分代码:

?
这部分和上面一部分类似,只不过由系统属性改为了系统环境变量,异常处理方式等也和上面一部分一样。这两部分都是为spring内部提供系统信息的支撑bean。

二、prepareBeanFactory()方法调用之后,是一个try-catch代码块,如果有BeanException异常产生则会停止refresh并且销毁已创建的资源,现在看代码块里的第一行postProcessBeanFactory(beanFactory)

postProcessBeanFactory()方法,默认方法体是空的,主要是用来扩展beanfactory的,扩展点是在bean等配置都已经加载但还没有进行实例化的时候。

例如上面说到的aware相关接口自动装配设置,假如是web项目,使用的是spring的webApplicationcontext,这时需要一些ServletContextAware相关的自动装配忽略及配置等,就需要在webApplicationContext里重写这个方法来实现相应功能。

refresh()方法中在上篇看到了postProcessBeanFactory(beanFactory),这篇继续往下看。

注:refresh()的代码就不再次列举了,请看spring源码中AbstractApplicationContext类。

一、invokeBeanFactoryPostProcessors(beanFactory),这个方法从名字就可以看出是在调用BeanFactoryProcessor,代码也比较长,分成几部分来看。

第1部分:

?
首先创建一个HashSet变量processedBeans,接着是个判断,如果beanFactory类型实现了BeanDefinitionRegistry接口,强转beanFactory对象为BeanDefinitionRegistry类型变量registry,创建两个LinkedList变量regularPostProcessors用来存储普通PostProcessor;registryPostProcessors用来存储一些用来对bean定义的注册信息进行处理的PostProcessor。
7-17行循环所有applicationContext中已经注册的BeanFactoryPostProcessor,如果是实现了BeanDefinitionRegistryPostProcessor的类型,则调用对应的postProcessBeanDefinitionRegistry()方法进行相应处理并加入到registryPostProcessors中,否则加入到regularPostProcessors中。
18-25行首先调用BeanFactory的getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)方法获取所有类型为BeanDefinitionRegistryPostProcessor的bean,然后放到List对象registryPostProcessorBeans中并且进行排序,排序之后循环调用每个bean的postProcessBeanDefinitionRegistry()方法。

注:getBeansOfType()后续会有一个针对beanFactory的专门研究先不做详细分析,这里简单说一下排序,spring内部实现了一套排序方法,主要是一个Ordered接口,需要排序的对象实现这个接口的getOrder()方法,在进行排序的时候会对这个结果进行比较从而实现排序。另外假如某个对象实现的是PriorityOrdered接口则优先进行排序,同样情况则依旧比较getOrder()的结果。
26-28行依次对3个List对象调用invokeBeanFactoryPostProcessors()方法,进行BeanFactoryPostProcessor的处理,顺序为registryPostProcessors、registryPostProcessorBeans、regularPostProcessors。invokeBeanFactoryPostProcessors()方法的代码很简单,就是for循环调用每个postProcessor对象的postProcessBeanFactory(beanFactory)方法。
29行把所有bean中加载过来的BeanDefinitionRegistryPostProcessor类型的bean的名字加入到processedBeans中。
回到上面最开始的判断,如果beanFactory类型没有实现BeanDefinitionRegistry接口,则直接调用invokeBeanFactoryPostProcessors()方法处理所有ApplicationContext已注册的BeanFactoryPostProcessor。

第2部分:

?
第1、2行首先获取所有类型为BeanFactoryPostProcessor的bean的name集合放到变量postProcessorNames
第3行建立一个ArrayList变量priorityOrderedPostProcessors用来存储需优先处理的postProcessor
第4、5行分别建立两个ArrayList变量orderedPostProcessorNames、nonOrderedPostProcessorNames用来存储有排序的和无排序的postProcessor
第6-19行循环上面获取到的所有postProcessor的name集合,按条件进行不同处理:

如果name已经存在于processedBeans则代表是已经处理过了,跳过这一个;

调用isTypeMatch()方法根据bean的name判断该bean是否实现了PriorityOrdered接口(上面我们说过排序中这个属于优先排序),如果是的话根据该name取出对应的bean对象加入到priorityOrderedPostProcessors集合中;

调用isTypeMatch()方法根据bean的name判断该bean是否实现了Ordered接口(上面我们说过实现了这个接口就可以进行排序了),如果是的话把该name加入到orderedPostProcessorNames集合中;

如果都上面条件都不成立,则加入到nonOrderedPostProcessorNames集合中;

注:关于isTypeMatch()方法,说起来简单就是根据bean的name取出bean对象然后进行类型判断,但实际上这个方法并不简单,最终主逻辑代码在AbstractBeanFactory中,做个标记,以后单独抽出来分析一下。
第20行对priorityOrderedPostProcessors进行排序
第21行调用invokeBeanFactoryPostProcessors()方法对priorityOrderedPostProcessors中的所有postProcessor进行处理
第23-28行通过getBean()方法取得所有orderedPostProcessorNames集合中postProcessor的bean对象,然后加入到一个新的集合变量orderedPostProcessors中,然后对这个集合排序,最后调用invokeBeanFactoryPostProcessors()方法处理
后面的一部分是对无排序的nonOrderedPostProcessorNames进行处理,除了去掉排序步骤之外和上面的步骤一样,就不重复描述了

二、我们回到refresh()方法中,看下一行:registerBeanPostProcessors(beanFactory),这个方法主要就是对BeanPostProcessor的注册,依旧分为几部分来看:

第1部分:

?
第1行获取所有的BeanPostProcessor类型的bean的name数组
第2行计算BeanPostProcessor的数量:banFactory中已注册的BeanPostProcessor的数量 + 1 + 上面获取到的所有bean中的BeanPostProcessor的数量。这里面的那个+1,是下一行的BeanPostProcessorChecker
第3行注册一个BeanPostProcessorChecker到beanFactory中,这个BeanPostProcessor作用是当一个bean创建后没有被所有的BeanPostProcessor处理的时候打印一行info级别日志

第2部分:

?
这部分代码与BeanFactoryPostProcessor的处理那部分类似,就是把所有的BeanPostProcessor进行区分放到不同集合里,优先的、排序的、无排序的。有个特殊的地方就是多了一个internalPostProcessors集合,用来存放优先级别中类型为MergedBeanDefinitionPostProcessor的BeanPostProcessor。它的主要作用是在spring运行时合并处理bean定义,例如注解中的bean定义,这部分也还没完全弄清楚,做个标记,回头专项分析。

第3部分:

?
第1-2行对priorityOrderedPostProcessors进行排序,并调用registerBeanPostProcessors()方法进行注册处理,这个方法内部代码比较简单,就是循环这个集合并调用beanFactory.addBeanPostProcessor(postProcessor)把每个BeanPostProcessor注册到beanFactory。
第3-13行和之前也类似了,把所有orderedPostProcessorNames中的BeanPostProcessor取出来放到集合里,其中MergedBeanDefinitionPostProcessor类型的依旧加入到internalPostProcessors中。最后两行先排序,再调用registerBeanPostProcessors()方法进行注册处理
第14-23行是对nonOrderedPostProcessorNames的处理,相比上面去掉了排序过程,其他依旧。
紧接着的是对internalPostProcessors排序,注册处理。
最后一行注册了一个BeanPostProcessor:ApplicationListenerDetector,这个是AbstractApplicationContext的内部类,实现了MergedBeanDefinitionPostProcessor接口,这个类只是暂时知道是在处理ApplicationListener相关的东西,具体作用还未知,留待分析。

refresh()方法中在上篇看完了对PostProcessors的处理,这篇继续往下看。

注:refresh()的代码就不再次列举了,请看spring源码中AbstractApplicationContext类。

一、initMessageSource(),这个方法是对spring的MessageSource初始化,代码如下:

?
首先获取beanFactory对象,然后判断是否定义了名为messageSource的localbean,如果有则执行第1部分,否则执行第2部分,分别来看两部分代码

注:localbean实际上就是指查找的时候不会去parent查找这个bean,只从当前beanfactory去查找,很多地方有这个就不一一注明了

第1部分:

?
第1行获取名为messageSource的bean赋值给当前ApplicationContext对象的messageSource属性
第2行判断如果当前ApplicationContext的parent不为null;并且messageSource对象继承了HierarchicalMessageSource接口则进行如下处理:

进行判断如果messageSource的parentMessageSource为空,则设置为getInternalParentMessageSource()方法的返回值。getInternalParentMessageSource()方法的代码也很简单

(getParent() instanceof AbstractApplicationContext) ? ((AbstractApplicationContext) getParent()).messageSource : getParent()

如果当前ApplicationContext的parent对象是AbstractApplicationContext或其子类类型则返回它的messageSource,否则直接返回其parent对象
最后是打印一行debug级别日志表示当前应用的messageSource

第2部分:

?
第1行创建一个DelegatingMessageSource对象dms
第2行类似上面,设置dms的parentMessageSource为getInternalParentMessageSource()返回值
第3行设置当前ApplicationContext的messageSource属性为dms
第4行把这个对象注册一个名为messageSource的单例bean
打印一行debut日志表示无用户定义messageSource,使用默认

二、紧接着处理完messageSource的初始化后下一行代码:initApplicationEventMulticaster(),主要是对spring的事件监听器的管理器的初始话,代码如下:

?
和messageSource的处理类似,首先取得beanFactory对象,
判断如果用户主动定义了applicationEventMulticaster的bean,则把这个bean设置给applicationEventMulticaster属性
如果没有则初始话一个默认的SimpleApplicationEventMulticaster,注册bean并赋值给对应属性
不同情况分别打印不同的日志,源代码中的日志打印最好也稍微注意一下有个印象,这样在看spring的日志时会更清晰

三、接下来是一个模板方法onRefresh(),第一篇中提到过这个是在处理messageSource、applicationEventMulticaster等特殊bean后,普通单例bean没初始话之前,为ApplicationContext子类提供扩展去处理一些类似的特殊bean。

举个例子AbstractRefreshableWebApplicationContext、GenericWebApplicationContext、StaticWebApplicationContext中都有一个themeSource,这个就要放在这个方法里去初始化。这个themeSource是spring的主题功能,可以实现根据不同主题加载不同资源文件等功能。

四、上面处理了事件监听器的管理器初始化,现在开始做时间监听器的注册:registerListeners(),这个方法的代码如下:

?
上面3行是处理当前ApplicationContext中的静态特殊监听器集合,循环调用applicationEventMulticaster的addApplicationListener()方法注册到applicationEventMulticaster中
后面的一部分首先取出所有类型为ApplicationListener的bean的name集合,然后循环调用applicationEventMulticaster的addApplicationListenerBean()方法注册到applicationEventMulticaster中
注意上面两个注册方法的不同,分别会注册到applicationEventMulticaster.defaultRetriever的不同集合中

本篇分别看到了messageSource、applicationEventMulticaster和applicationListener以及中间提到的主题themeSource的初始化,这里主要介绍初始话,所以后续再对spring的这几个功能模块做分别详细的分析。

refresh()方法中在上篇看完了MessageSource及时间监听器等初始话处理,这篇继续往下看。

注:refresh()的代码就不再次列举了,请看spring源码中AbstractApplicationContext类。

一、finishBeanFactoryInitialization(beanFactory)这个方法将完成BeanFactory的初始化,主要做的事就是初始化除了之前处理过的特殊bean之外的所有单例bean,代码如下:

?
第1-5行判断如果定义了名为conversionService并且类型为ConversionService的bean,则把其设置为beanFactory的conversionService属性。这个主要是用来提供数据转化服务的
销毁之前在prepareBeanFactory()中生成的临时ClassLoader
freezeConfiguration()的代码如下:

?
这个方法就是代表bean定义等配置已经可以缓存了,不会再有其他地方对其做修改了
最后一行就是对所有非延迟加载的单例bean进行初始化了我们来看下这个方法的代码:

?
首先是一行info级别的日志,然后在对象beanDefinitionMap的同步下循环所有bean的name分别进行初始化

首先获取bean定义信息对象bd,然后进行判断,这里只对非抽象bean(抽象bean是用于继承定义配置等信息的不可初始化)、单例、非延迟加载的bean进行处理

判断如果是FactoryBean则进行下面的处理,如果不是直接调用getBean(beanName),这个方法调用会进行这个bean的初始化,关于这个方法还是放到BeanFactory的单独分析里面这里就不往里看了。

对于FactoryBean的获取,要在beanname前加上一个&,然后会先判断是否是SmartFactoryBean并且渴望初始化(EagerInit),如果是才调用getBean(beanName),否则这个应该是在第一次调用工厂的getObject的时候才初始化

注:对于这中间AccessController.doPrivileged的运用没有搞明白,留待以后分析,不知道为什么要在这里使用这个

二、最后的一个处理是finishRefresh()方法,代码如下:

?
1.先看initLifecycleProcessor()方法的代码:

?
这个方法主要是用来初始化生命周期管理器LifecycleProcessor的

如果用户定义了名为lifecycleProcessor类型为LifecycleProcessor的LocalBean,则赋值给当前ApplicationContext的lifecycleProcessor属性
如果用户没有定义,则初始化默认的生命周期管理器DefaultLifecycleProcessor,注册单例bean,并赋值给lifecycleProcessor属性

2.initLifecycleProcessor()方法之后则是对生命周期管理器的触发,LifecycleProcessor有两个触发点onRefresh()和onClose(),当前正处于refresh所以调用其onRefresh()方法

3.调用publishEvent()方法发布ContextRefreshedEvent事件,[b]publishEvent()的代码也很简单就不介绍了,就是调用当前上下文及parent的ApplicationEventMulticaster的multicastEvent()方法,这个放到分析事件处理模块时再去详细分析。[/b]

三、最后分析一下在整个try代码块中如果抛出异常的处理,可以看到分为了两个方法调用:

1.destroyBeans()代码很简单,就是调用BeanFactory的destroySingletons()方法销毁所有单例bean。还是暂不细看放到BeanFactory专项分析里去

2.cancelRefresh()这个方法代码看一下:

?
就是在同步下设置状态值而已,但是有个小细节,这个方法在AbstractRefreshableApplicationContext和GenericApplicationContext两个子类中进行了重写,但是也很简单,就是增加了一个beanFactory.setSerializationId(null)然后依旧调用上面super中的方法进行修改状态

关于ApplicationContext的基本初始化的过车这就分析完了,中间碰到了很多问题,也还有很多地方需要详细研究,下面列举备忘一下,后面挨个分析:

bean定义的加载
bean的初始化
BeanFactory的一些核心方法
BeanFactory和ApplictionContext的关系以及各自的类继承框架
扩展点BeanFactoryPostProcessor及BeanPostProcessor
事件监听器ApplicationListener
信息管理器MessageSource
属性编辑器PropertyEditor
生命周期管理器LifecycleProcessor
还有几个小细节例如LoadTimeWeaver、MergedBeanDefinitionPostProcessor、AccessController.doPrivileged等
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: