Spring 浅谈

来源:互联网 发布:python 2.7安装 编辑:程序博客网 时间:2024/04/30 00:16
以下部分摘自网络:

Spring启动过程, 可以概括为以下几步:
定义->定位->装载->注册->创建->注入

在容器启动的时候完成:定义 -〉定位 -〉装载
在客户向容器要求bean的时候完成: 创建 -〉注入


  定义:
类似application.xml资源文件,所有的bean定义信息都在这个文件中描述.且依赖于dtd/xsd的规则.

  定位:对于资源文件信息的封装需要依赖Resource对象.当然这里的Resource仅仅存放了资源文件的简单信息,比如文件(名)和路径等等.所以这就需要ResourceLoader来用于对资源的辅助加载.其中以DefaultResourceLodaer为例,如果通过ClassPathResource方式来加载,就需要指定ClassLoader,这也就是为什么以classpath方式加载资源文件,通常将把资源文件放置于source path下而以file system方式加载则以工程相对路径.比如/WEB-INF/application.xml.这里值得说明的是ApplicationContext实现了ResourceLoader接口,因此他本身就是个资源解析器,通过构造方法就能直接加载资源文件.此外spring自带了常用的资源加载绑定类,当然也可以自己来实现这个Resource接口,比如通过网络获取2进制数据对象反序列化的方式.

  装载:BeanDefinitonReader的loadBeanDefine方法用于对Resource的解析处理,另外还对资源文件定义的合法性进行校验.同大多资源文件解析相同,通过w3c开源框架对所有element做迭代处理.但是这里的DeanDefinitonReader只是对BeanDefinitonParserDelegate的套壳处理.也就是说真正对资源文件定义做每个标签和属性做读取解析的最终类,就是BeanDefinitonParserDelegate.因此从命名不难发现,对定义进行解析后最终得到的数据模型,就是BeanDefiniton对象.每个BeanDefiniton对象封装了对应bean定义的所有信息.这个有些类似于o-r(x) mapping实现思想.需要重点说明的是,这里仅仅作为bean信息个定义封装,而并没有产生任何与bean实例以及相关属性实例.

  注册:这个过程比较简单,以DefaultListableBeanFactory为例,或常用的AbstractXmlApplicationContext及其实现的子类,都无非将装载时获取的所有BeanDefinition对象存放到beanDefinitionMap对象中,这个beanDefinitionMap是个标准的Map对象.当然作者处于对BeanDefinition的顺序检索处理,还特地定义了beanDefinitionNames,这个beanDefinitionNames是个List对象.这2个对象就是存放bean(定义)的场所,或许也是真正意义的容器概念.因为今后所有客户端对容器的请求发起,作为容器方都将从该Map中取得相关bean信息.而不再持久资源文件中做任何读取操作.

  创建:当客户端对已经初始化的容器发起请求时,容器首先会以bean name为key从beanDefinitionMap中获取BeanDefiniton定义对象.接着对singleton bean进行预实例化的处理.随后会从BeanDefiniton定义对象中对当前定义的bean对象做实例化操作,这里调用了AbstractAutowireCapableBeanFactory的createBean方法,注意目前到这个层面仅仅对bean本身的实例化(以prototype为例也就相当于进行了new操作).这其中首先会对实例化方式进行判断,比如工厂模式或者原型模式(包括带参数构造),如遇到带参数的构造定义,则需要进步解析构造参数,这个解析过程类似与当前bean的属性注入的过程.在下文中将做详细介绍.最后当前给请求的bean通过反射来实例化对象.

  注入:这个过程是所有容器工作步骤中最为复杂的部分.首先这里有个对依赖的检查过程.虽然通过调用getBean的方式处理,但仅仅为了做依赖检查而不返回被依赖的对象.这样的目的在于将校验提前进行,而不要等到对于开销较大的依赖注入时.接下来createBean开始调用populateBean方法.首先进行自动装配模式的处理,也就是说对BeanDefiniton中定义自动装配模式的属性进行调整.比如定义了AUTOWIRE_BY_NAME的属性会相应找到匹配该命名的bean.并且将该被检索到的bean实例值给property,当然这里也肯定通过getBean方法来获取这个需要自动装配的bean实例,并且在BeanWrapper中包装.其实下文要讲到的注入过程也在BeanWrapper中完成.说道这里,可以明显看出,1个普通bean(既1个bean,包含1个或多个简单的属性)的属性注入过程,也需要依赖BeanWrapper来完成.或者说当得到1个bean的所有property定义时,容器首先将根据property的不同类型,如prop,map,list,set当然还有ref(在BeanDefinitionValueResolver的resolveValueIfNecessary方法完成),进行不同方式的对象实例化,当得知了属性的类型后就可以通过该类中相关resolve方法来完成该属性需要注入的对象的实例化操作,比如1个prop类型的属性可能就通过简单的new操作外加setProperty操作来完成了.而之所以可以通过类型检查来进行判断,是因为在BeanDefiniton定义中已经对这些property value做了封装处理,这可能也是最好用于区分property类型的最佳方式.具体的封装过程可以参考BeanDefinitonParserDelegate的parsePropertyValue方法.这里最最最值得提及的是,在该类resolveReference方法中,容器依旧通过getBean来获取需要被注入的bean对象,因此这里还需要进行1次依赖检查.如果该被注入的bean对象又依赖其他bean对象,那将重复上述过程.因此说创建与注入是个递归的过程.而最后完成对bean注入,也就是通常我们所谓的setter方法的,又需要回到BeanWrapper类,这里的setPropertyValue方法比较复杂,但我们可以暂且不必关心他的实现,因为写到这里我们已经知道了属性需要被注入的对象,在setPropertyValue只是将该对象进行赋值的操作
0 0
原创粉丝点击