怎么怎样阅读spring源码码

当前位置:
看透Spring MVC:源代码分析与实践
用户还喜欢
勒庞可能是世界上最蔑视群体的人,同时也是最了解群体的人。他在1895年完成的《乌合之众》以预言家般的洞察力,几乎成功描述了此后一百多年间所有震荡世界的重大事件。包括两次世界大战和众多的民主革命或群众运动。有人指责勒庞关于群体与领袖的理论曾被希特勒、墨索里尼等独裁政权所用。但戴高乐、丘吉尔、罗斯福也从中悟到了不少道理。时至今日,任何个人或者团体,出于任何目的希望了解群体心理和行为模式,《乌合之众》仍然是首选经典。本书尤其适合在中国当下阅读。
《Spring技术内幕:深入解析Spring架构与设计原理》是Spring领域的问鼎之作,由业界拥有10余年开发经验的资深Java专家亲自执笔!Java开发者社区和Spring开发者社区一致强烈推荐。国内第一本基于Spring3.0的著作,从源代码的角度对Spring的内核和各个主要功能模块的架构、设计和实现原理进行了深入剖析。你不仅能从木书中参透Spring框架的优秀架构和设计思想,而且还能从Spring优雅的实现源码中一窥Java语言的精髓。此外,《Spring技术内幕:深入解析Spring架构与设计原理》还展示了阅读源代码的卓越方法,不仅授你以鱼,而且还授你以渔!如果你以一种淡定的心态翻开这本书,无论你是Java程序员、Spring开发者,还是平台开发人员、系统架构师,抑或是对开源软件源代码着迷的代码狂人,都能从《Spring技术内幕:深入解析Spring架构与设计原理》中受益。《Spring技术内幕:深入解析Spring架构与设计原理》特色:作者从业10余载,悟透Spring等开源软件的本质,权威性毋庸置疑。Java开发者社区、专业Spring开发者社区和架构师社区一致鼎力推荐!深入解析Spring架构原理与设计思想,探究Spring成功的奥秘。揭开Spring源代码的神秘面纱,展示系统阅读开源软件源代码的方法和秘诀。如果你正在思考下面这些问题,也许《Spring技术内幕:深入解析Spring架构与设计原理》就是你想要的!掌握Spring的架构原理与设计思想真的能让开发者如虎添翼吗?IoC容器如何掌控以POJO为基础的Bean对象?它的轻量级开发设计思想是如何实现的?Spring产品级的IoC容器是如何作为一个完整的系统实现并运行的?它如何启动?如何完成Bean的解析和载入?又如何实现Bean的生命周期管理?Spring如何简捷地在JVM上实现AOP功能?Spring AOP如何实现Aspect编织功能?Spring如何实现各种数据库操作组件的集成?Spring如何在Web环境中集成IoC容器并为Web应用开发提供利器?我们耳熟能详的MVC模式在Spring中是如何实现的?Spring MVC如何灵活地集成各种丰富的视图展现方案?Spring实现远端调用的方案有很多种,你知道它们之间的优劣差异吗?Spring ACEGI安全框架在用户验证和授权机制的实现上有何过人之处?如何在Spring的基础上进行扩展开发?你是否曾经也有过分析开源软件源代码的冲动?你想掌握分析源代码的最佳实践吗?……
本书由Hadoop领 域资深的实践者亲自执笔,首先介绍了MapReduce的 设计理念和编程模型,然后从源代码的角度深入分析 了RPC框架、客户端、JobTracker、TaskTracker和 Task等MapReduce运行时环境的架构设计与实现原理 ,然后从实际应用的角度深入讲解了Hadoop的性能优 化、安全机制、多用户作业调度器和下一代 MapReduce框架等高级主题和内容。《Hadoop技术内 幕(深入解析MapReduce架构设计与实现原理)》适 合Hadoop的二次开发人员、应用开发工程师、运维工 程师阅读。
《Spark大数据处理:技术、应用与性能优化》是一本依据最新技术版本,系统、全面、详细讲解Spark的著作,作者结合自己在微软和IBM的实践经验和对Spark源代码的研究撰写而成。首先从技术层面讲解了Spark的体系结构、工作机制、安装与部署、开发环境搭建、计算模型、Benchmark、BDAS等内容;然后从应用角度讲解了一些简单的、有代表性的案例;最后对Spark的性能优化进行了探讨。
《大师的境界:谈“生”论“死”》,这是一部透过“生”与“死”来研究和探寻人生和人生意义的著作。它从大师们人生的各个侧面和各种表象入手,博采百家,见人所未见,言人敢未言,通过丰富多彩的事例和生动活泼的语言,形象地阐述了“生”与“死”的问题,引入深入认识人生,思考人生,品味人生,激励人们去直面人生。
看透Spring MVC:源代码分析与实践
(3人评分)
分&&&&类:
作&&&&者:
字&&&&数:39.3万
点&&&&击:20.3万
授权方:授权作品,不得转载
标&&&&签:
目录(105章)
壕,余额不足了
呜~月票不足
呜~你还没有月票
网易公司版权所有©
网易邮箱登录
其他帐号登录:
在客户端“资讯”首页刷新后,即可阅读此内容。
在客户端“书籍”首页刷新后,即可阅读此书籍。
还差两步,你就能在客户端上阅读此内容。
排序保存成功!8154人阅读
Spring(4)
前面写了几篇spring 的介绍文章,感觉与主题不是很切合。重新整理下思路,从更容易理解的角度来写下文章。
spring 的骨架
spring 的骨架,也是spring 的核心包。主要包含三个内容
1.context:spring 的上线文-------导演
2.core:spring的核心包,主要包括spring所以用到的工具-------道具
3.beans:spring的bean实例 -------演员
导演负责安排演出,演员负责按照导演的指示来演出,演出过程中需要使用道具。
我想大家看完这些图片之后就明白大致的包关系了。
spring包结构
大家看到相应包内容。
core包侧重于帮助类,操作工具,beans包更侧重于bean实例的描述。context更侧重全局控制,功能衍生。
下面我们就针对context和factory对类的关系继续一个基本概括:
核心类之间的关系
我们先来看下bean包下的beanfactory类,以及抽象类等。
可以看到在接口的实现泛化的过程中,每一个接口在继承父接口的同时,也继承了父接口的一些方法。这就可以看出面向接口变成微妙之处。
BeanFactory【所有BeanFactory的父类】
可以看到beanfactory中定义了一些基本方法,包括根据名称获取bean实例等。
HierarchicalBeanFactory【层次化的BeanFactory】
可以看到此接口实现了层次化,及获取beanFactory的父容器
LisableBeanFactory列表式Beanfactory
可以看到为beanfactory设置了列表的功能,并且规划了如何从列表中取出相应的方法的能力。
从上述类命名以及接口规划可以看到,通过接口的不断继承,beanfactory被不断的丰富抽象起来。层层细分之后,没有个类都的职责都变的单一了,同时在扩展该的属性时也变的更加方便。针对源代码,最好的办法还是根据名称来,最方便。
context【上下线文】
可以看到到了context的初始化不同于beanfactory,可以侧重于抽象类型,具体的方法实现。
里面大部分方法使用了模板方法的设计模式,父类调用抽象方法,抽象方法在子类中实现,对象的独立性。
主要分成三种context:XML,Annotation,Groovy针对三种形式。
registry【实例或者bean描述注册器】
将初始化完成的bean注册的容器中,针对单例来部分,缓存单例实例。针对beanDefinition部分,缓存bean描述。
Strategy【初始化策略】
两种初始化策略 一种是简单策略,一种是cgilib的策略,当时这里使用的模式是策略模式。
context的初始化
* 在parent下创建ClassPathXmlApplicaitonContext,
* 从XML中读取所有Bean定义.
* @param configLocations 配置文件路径如c:\simpleContext.xml
* @param refresh 是否需要自动刷新context,refresh--&重新加载
* 加载所有的bean定义,创建所有单例.
* refresh为true的时候, 根据context来手工刷新
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
//初始化XmlApplicationContext
super(parent);
//转换配置文件的路径
setConfigLocations(configLocations);
if (refresh) {
//重新刷新原有的context,这一篇的重点
refresh();
下面我们来看下AbstractApplicationContext.refresh()方法
//加载或刷新持久的配置,可能是xml文件,properties文件,或者关系型数据库的概要。
//做为一个启动方法,如果初始化失败将会销毁已经创建好的单例,避免重复加载配置文件。
//换句话说,在执行这个方法之后,要不全部加载单例,要不都不加载
public void refresh() throws BeansException, IllegalStateException
synchronized (this.startupShutdownMonitor)
// 初始化配置准备刷新,验证环境变量中的一些必选参数
prepareRefresh();
// 告诉继承类销毁内部的factory创建新的factory的实例
// 初始化Bean实例
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 初始化beanFactroy的基本信息,包括classloader,environment,忽略的注解等
prepareBeanFactory(beanFactory);
// beanfactory内部的postProcess,可以理解为context中PostProcess的补充
beanFactory.postProcessBeanFactory(beanFactory);
// 执行BeanFactoryPostProcessor(在beanFactory初始化过程中,bean初始化之前,修改beanfactory参数)、
// BeanDefinitionRegistryPostProcessor 其实也是继承自BeanFactoryPostProcessor,
// 多了对BeanDefinitionRegistry的支持invokeBeanFactoryPostProcessors(beanFactory);
// 执行postProcess,那BeanPostProcessor是什么呢,是为了在bean加载过程中修改bean的内容,
// 使用分的有两个而方法Before、After分别对应初始化前和初始化后
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource,主要用作I18N本地化的内容
initMessageSource();
// 初始化事件广播ApplicationEventMulticaster,使用观察者模式,对注册的ApplicationEvent时间进行捕捉
initApplicationEventMulticaster();
// 初始化特殊bean的方法
onRefresh();
// 将所有ApplicationEventListener注册到ApplicationEventMulticaster中
registerListeners();
// 初始化所有不为lazy-init的bean,singleton实例
finishBeanFactoryInitialization(beanFactory);
// 初始化lifecycle的bean并启动(例如quartz的定时器等),如果开启JMX则将ApplicationContext注册到上面
finishRefresh();
catch (BeansException ex)
//销毁已经创建单例
resources.destroyBeans();
// 将context的状态转换为无效,标示初始化失败
flag.cancelRefresh(ex);
// 将异常传播到调用者
我们从时序图来看启动上述初始化(门面模式facade)
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:334467次
积分:2800
积分:2800
排名:第9811名
原创:65篇
转载:36篇
评论:67条
阅读:14312
(1)(3)(1)(4)(31)(1)(1)(1)(2)(2)(16)(1)(7)(9)(6)(6)(2)(4)(3)  最近没什么实质性的工作,正好有点时间,就想学学别人的代码。也看过一点源码,算是有了点阅读的经验,于是下定决心看下spring这种大型的项目的源码,学学它的设计思想。
  手码不易,转载请注明:
  这篇博文你可以了解到:
  1 Spring jar包以及源码使用
  2 简单的spring运行示例
  3 利用断点调试程序,如何快速的阅读程序【快捷键等的使用】
  这次阅读的源码比较老了,是3.0.5版本的,由于正好手头有这个版本的源码,而且平时基本上也是用的这个版本Spring,因此后文的分析也都是针对这个版本。
  下面贡献一下,由于百度云上传的压缩包总是解压失败,就放在csdn上面了。
如何使用jar包以及源码的source包
  首先,在工程右键,属性中,添加必要的jar包。
  选中必要的jar包,上面给出的源码jar包中,导入spring3.0.5中的所有jar包。
  其中lib内的是spring的jar包,用到哪个导入哪个,不知道的话,全部导入就行了。
  外面的几个jar包,用于日志以及mysql的驱动。commons-logging jar包是必须的,其他的随意吧。
  不确定的话,lib外面的这几个jar包以及lib里面的都导入就行了。
  导入jar包后,点开jar包,选中source attachment进行编辑,链接到源码的jar包。
  选择相应的source源码包
  全部导入后,如下
spring样例
  首先是一个必要的POJO类,用于注入属性的值。
1 package com.test.
3 public class Person {
private int
public String getName() {
public void setName(String name) {
this.name =
public int getAge() {
public void setAge(int age) {
this.age =
public void info(){
System.out.println("name:"+getName()+" age:"+getAge());
  主函数,用于读取资源文件,获取bean,调用info方法
1 package test.
3 import org.springframework.context.ApplicationC
4 import org.springframework.context.support.ClassPathXmlApplicationC
6 import com.test.bean.P
8 public class Test {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");//读取bean.xml中的内容
Person p = ctx.getBean("person",Person.class);//创建bean的引用对象
  bean.xml用于配置bean的资源文件
1 &?xml version="1.0" encoding="UTF-8"?&
2 &beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"&
&bean id="person" class="com.test.bean.Person"&
&property name="name" value="xingoo"/&
&property name="age" value="12"/&
10 &/beans&
  运行结果
  首先,有了前面的jar包以及源码包,你就可以通过这个简单的程序,进行但不的调试,阅读源码。
  简单的说下调试的快捷键:
  1 F5:下一步,可以进入下一个函数栈
  2 F6:当前函数的下一步,不会进入其他的函数。
  3 F8:下一个断点。
  4 也可以通过选中一个变量或者表达式,按ctrl+shift+i 来查看内容。或者添加监视的方式,查看。
  5 可以通过快捷键F2,来查看一个函数方法的javadoc,即说明
  6 快捷键F3或者ctrl+鼠标点击,进入一个函数
  7 ctrl+shift+G 查看当前方法都有谁在使用
  8 F4查看类的继承关系,可以向上显示出类继承的父类以及接口。
  有了调试的方法,接下来,就是如何阅读源码了!
  1 参考书籍,推荐《Spring技术内幕》
  这本书,基本上很详细的讲述了,spring的实现方式,以及类之间的复杂关系。可以帮助你快速的理清复杂的类之间的关系。
  2 使用StarUML画类图
  比如你好不容易理清了一个部分的关系,很快就会忘记其中的关系,那么可以通过这个工具,简单的画出其中的复杂关系。
  这样,下一次看的时候也会清楚一些,这是我今天刚画好的ClassPathXmlApplicationContext的类图关系:
阅读(...) 评论()随笔 - 81&
文章 - 266&
trackbacks - 0
2728293031123456791011121314151617181920222324252627283031123456
说我博客名字,给你们打折!
好友的BLOG
阅读排行榜
评论排行榜
一个applicationContext.xml配置文件,这个不可少
一个bean,这里我没用接口,直接用一个普通的类做为Spring的bean
一个Junit测试类
applicationContext.xml
&?xml&version="1.0"&encoding="UTF-8"?&
&!DOCTYPE&beans&PUBLIC&"-//SPRING//DTD&BEAN&2.0//EN"&"http://www.springframework.org/dtd/spring-beans-2.0.dtd"&
&&&&&bean&id="studentBean"&class="my.StudentBean"&&/bean&
StudentBean
public&class&StudentBean{
&&&&public&void&getName(String&name)&{
&&&&&&&&System.out.println("你的名字是:"&+&name);
单元测试类
&1&public&class&MyTest&{
&3&&&&&public&static&void&main(String[]&args)&{
&4&&&&&&&&&ClassPathResource&res&=&new&ClassPathResource("my/applicationContext.xml");
&5&&&&&&&&&
&6&&&&&&&&&XmlBeanFactory&bf&=&new&XmlBeanFactory(res);
&7&&&&&&&&&
&8&&&&&&&&&StudentBean&bean&=&(StudentBean)bf.getBean("studentBean");
&9&&&&&&&&&
10&&&&&&&&&bean.getName("yangay");
运行单元测试,打印出“你的名字是:yangay”,测试类只有四行代码,但Spring到底为我们做了些什么?下面我们就基于这样的场景去分析bean的加载过程。
2. 初步分析
(1) 获取配置文件
ClassPathResource&res&=&new&ClassPathResource("my/applicationContext.xml");
&&& 这一句只是读入配置文件,并封装成Spring提供的Resource对象,供后面逻辑使用。&&& 在Spring内部,有超过十个以Resource结尾的类或文件,他们处理不同类型的资源文件,如FileSystemResource、ClassPathResource、UrlResource等,处理过程大同小异,内部细节可以不必关心,跟其他组件逻辑几乎没关系。
(2) 解析配置文件并注册bean
&XmlBeanFactory&bf&=&new&XmlBeanFactory(res);
&&& 这里面的逻辑相当复杂,涉及到众多Factory、Reader、Loader、BeanDefinition、Perser、Registry系列接口和类,但他们做的基本事情就是将applicationContext.xml配置的Bean信息构成BeanDefinition对象,然后放到Factory的map中(这一步就是所谓的注册),这样以后程序就可以直接从Factory中拿Bean信息了。&&& 要跟踪这个处理过程,大致流程如下:&&& a. 构造XmlBeanFactory时,会调用Reader对象的loadBeanDefinitions方法去加载bean定义信息&&& b. 在Reader对象的doLoadBeanDefinitions验证文档(配置文件)模式,然后通过documentLoader对象处理资源对象,生成我们Document对象;&&& c. 调用BeanDefinitionDocumentReader对象的doRegisterBeanDefinitions去注册bean定义信息;&&& d. parseBeanDefinitions从xml文档根节点递归循环处理各个节点,对bean节点真正的处理工作委托给了BeanDefinitionParserDelegate,方法parseBeanDefinitionElement将一个bean节点转换成一个BeanDefinitionHolder对象,这才是最终的解析过程;&&& e. DefaultListableBeanFactory.registerBeanDefinition利用解析好的beanDefinition对象完成最终的注册,其实就是把beanName和beanDefinition作为键值对放到beanFactory对象的map;
(3) 实例化Bean
StudentBean&bean&=&(StudentBean)bf.getBean("studentBean");
&&& 这一步Spring同样做了复杂的处理,但基本原理就是利用反射机制,通过bean的class属性创建一个bean的实例,例子中是创建了一个StudentBean对象。
(4) 调用对象的方法,没什么好说的。当然如果方法上做了事务、AOP之类的声明,这一步的处理就不会那么简单了。
3. 解析配置文件并注册bin对象
我们分析bean的注册过程,就是下面这行代码,他完成了配置文件的解析和bin的注册功能,我们看看Spring到底为我们做了多少事情。XmlBeanFactory&bf&=&new&XmlBeanFactory(res);public&class&XmlBeanFactory&extends&DefaultListableBeanFactory&{&&&&//这里为容器定义了一个默认使用的bean定义读取器&&&&private&final&XmlBeanDefinitionReader&reader&=&new&XmlBeanDefinitionReader(this);&&&&public&XmlBeanFactory(Resource&resource)&throws&BeansException&{&&&&&&&&this(resource,&null);&&&&}&&&&//在初始化函数中使用读取器来对资源进行读取,得到bean定义信息。&&&&public&XmlBeanFactory(Resource&resource,&BeanFactory&parentBeanFactory)&throws&BeansException&{&&&&&&&&super(parentBeanFactory);&&&&&&&&this.reader.loadBeanDefinitions(resource);&&&&}我们跟进去,发现他实际调用了XmlBeanDefinitionReader对象的loadBeanDefinitions方法。3.1 XmlBeanDefinitionReader.loadBeanDefinitionspublic&int&loadBeanDefinitions(Resource&resource)&throws&BeanDefinitionStoreException&{&&&&&&&&//封装资源文件&&&&&&&&return&loadBeanDefinitions(new&EncodedResource(resource));&&&&}InputStream&inputStream&=&encodedResource.getResource().getInputStream();&&&&&&&&&&&&try&{&&&&&&&&&&&&&&&&InputSource&inputSource&=&new&InputSource(inputStream);&&&&&&&&&&&&&&&&if&(encodedResource.getEncoding()&!=&null)&{&&&&&&&&&&&&&&&&&&&&inputSource.setEncoding(encodedResource.getEncoding());&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&return&doLoadBeanDefinitions(inputSource,&encodedResource.getResource());&&&&&&&&&&&&}这个方法是整个资源加载的切入点,我们先大致看看这个方法的处理流程: a. 封装资源文件&& &new EncodedResource(resource)b. 获取输入流&& &从EncodedResource对象中获取InputStream并构造InputSource对象c. 然后调用doLoadBeanDefinitions方法完成具体的加载过程3.2 doLoadBeanDefinitions方法int&validationMode&=&getValidationModeForResource(resource);Document&doc&=&this.documentLoader.loadDocument(inputSource,&getEntityResolver(),&this.errorHandler,&validationMode,&isNamespaceAware());return&registerBeanDefinitions(doc,&resource);这个方法的代码很长,如果不考虑异常处理,其实只做了三件事情:a. 获取对XML文件的验证模式b. 加载XML文件,并得到对应的Document对象c. 根据返回的Document对象注册bean信息这里对验证模式不进行讨论;这里不对Document对象的加载过程进行讨论;这里直接进入bean的注册方法registerBeanDefinitions3.3 registerBeanDefinitions方法&&&&public&int&registerBeanDefinitions(Document&doc,&Resource&resource)&throws&BeanDefinitionStoreException&{&&&&&&&&//&这里定义解析器,使用XmlBeanDefinitionParser来解析xml方式的bean定义文件&-&现在的版本不用这个解析器了,使用的是XmlBeanDefinitionReader&&&&&&&&if&(this.parserClass&!=&null)&{&&&&&&&&&&&&XmlBeanDefinitionParser&parser&=&&&&&&&&&&&&&&&&&&&&(XmlBeanDefinitionParser)&BeanUtils.instantiateClass(this.parserClass);&&&&&&&&&&&&return&parser.registerBeanDefinitions(this,&doc,&resource);&&&&&&&&}&&&&&&&&//&具体的注册过程,首先得到XmlBeanDefinitionReader,来处理xml的bean定义文件&&&&&&&&BeanDefinitionDocumentReader&documentReader&=&createBeanDefinitionDocumentReader();&&&&&&&&int&countBefore&=&getBeanFactory().getBeanDefinitionCount();&&&&&&&&documentReader.registerBeanDefinitions(doc,&createReaderContext(resource));&&&&&&&&return&getBeanFactory().getBeanDefinitionCount()&-&countB&&&&}当把文档转换为Document对象后,提取及注册bean就是我们的重头戏了。这里并没有看到我们想要的代码,而是把工作委托给了BeanDefinitionDocumentReader对象去处理3.4 BeanDefinitionDocumentReader.doRegisterBeanDefinitions方法&&&&public&void&registerBeanDefinitions(Document&doc,&XmlReaderContext&readerContext)&{&&&&&&&&this.readerContext&=&readerC&&&&&&&&Element&root&=&doc.getDocumentElement();&&&&&&&&BeanDefinitionParserDelegate&delegate&=&createHelper(readerContext,&root);&&&&&&&&preProcessXml(root);&&&&&&&&parseBeanDefinitions(root,&delegate);&&&&&&&&postProcessXml(root);&&&&}&&&&protected&void&parseBeanDefinitions(Element&root,&BeanDefinitionParserDelegate&delegate)&{&&&&&&&&if&(delegate.isDefaultNamespace(root.getNamespaceURI()))&{&&&&&&&&&&&&//这里得到xml文件的子节点,比如各个bean节点&&&&&&&&&&&&&&&&&&&&&NodeList&nl&=&root.getChildNodes();&&&&&&&&&&&&//这里对每个节点进行分析处理&&&&&&&&&&&&for&(int&i&=&0;&i&&&nl.getLength();&i++)&{&&&&&&&&&&&&&&&&Node&node&=&nl.item(i);&&&&&&&&&&&&&&&&if&(node&instanceof&Element)&{&&&&&&&&&&&&&&&&&&&&Element&ele&=&(Element)&&&&&&&&&&&&&&&&&&&&&String&namespaceUri&=&ele.getNamespaceURI();&&&&&&&&&&&&&&&&&&&&if&(delegate.isDefaultNamespace(namespaceUri))&{&&&&&&&&&&&&&&&&&&&&&&&&//这里是解析过程的调用,对缺省的元素进行分析比如bean元素&&&&&&&&&&&&&&&&&&&&&&&&parseDefaultElement(ele,&delegate);&&&&&&&&&&&&&&&&&&&&}else&{&&&&&&&&&&&&&&&&&&&&&&&&delegate.parseCustomElement(ele);&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&}&else&{&&&&&&&&&&&&delegate.parseCustomElement(root);&&&&&&&&}&&&&}经过艰难险阻,山路十八弯,我们终于走到了核心逻辑的底部doRegisterBeanDefinitions,如果说以前一直是XML加载解析的准备阶段,那么这个方法算是真正地开始进行解析了,我们期待的核心部分真正开始了。这个方法的代码我们比较熟悉,读取Document对象,循环每一个bean节点,然后进行处理。Spring有两类Bean,一个是默认的,一个是自定义的bean,这个方法对他们分别调用了不同方法进行处理。3.5 对默认标签的处理 processBeanDefinition方法&&&&protected&void&processBeanDefinition(Element&ele,&BeanDefinitionParserDelegate&delegate)&{&&&&&&&&BeanDefinitionHolder&bdHolder&=&delegate.parseBeanDefinitionElement(ele);&&&&&&&&if&(bdHolder&!=&null)&{&&&&&&&&&&&&bdHolder&=&delegate.decorateBeanDefinitionIfRequired(ele,&bdHolder);&&&&&&&&&&& BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,&getReaderContext().getRegistry());&&&&&&&&&&&&getReaderContext().fireComponentRegistered(new&BeanComponentDefinition(bdHolder));&&&&&&&&}&&&&}a. 首先利用委托类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder对象bdHolder,经过这个方法,bdHolder实例已经包含我们配置文件中对bean的所有配置信息了,如name、class等。b. 对bdHolder进行装饰c. 解析完成后,要对bdHolder进行注册,同样,注册过程委托给了BeanDefinitionReaderUtils去处理3.6 delegate.parseBeanDefinitionElement(ele)这个方法便是对默认标签解析的全过程了,他将一个element节点转换成BeanDefinitionsHolder对象,其中ele和bdHolder中的属性是对应的。不论是常用的还是不常用的我们都看到了,尽管有些复杂属性还需要进一步解析,但丝毫不会影响我们兴奋的心情。a. 提取元素的id和name属性b. 进一步解析其他所有属性并统一封装到BeanDefinition类型的实例c. 将获取到的信息封装到BeanDefinitionHolder实例中待续。。。String&id&=&ele.getAttribute(ID_ATTRIBUTE);String&nameAttr&=&ele.getAttribute(NAME_ATTRIBUTE);AbstractBeanDefinition&bd&=&createBeanDefinition(className,&parent);parseBeanDefinitionAttributes(ele,&beanName,&containingBean,&bd);bd.setDescription(DomUtils.getChildElementValueByTagName(ele,&DESCRIPTION_ELEMENT));&&&&&&&&&&&&parseMetaElements(ele,&bd);parseLookupOverrideSubElements(ele,&bd.getMethodOverrides());parseReplacedMethodSubElements(ele,&bd.getMethodOverrides());parseConstructorArgElements(ele,&bd);parsePropertyElements(ele,&bd);parseQualifierElements(ele,&bd);return&new&BeanDefinitionHolder(bd,&beanName,&aliasesArray);跟进去,我们就看到解析的最底层了,如parseMetaElements,这里不再进行往下分析。对于配置文件,解析也解析完了,装饰也装饰完了,已经把xml中bean元素的各属性封装到了BeanDefinition对象,已经可以满足后续的使用要求了,剩下的工作便是注册解析的BeanDefinition。3.7 BeanDefinitionReaderUtils.registerBeanDefinition这个方法并没有做太多事情,而是直接调用了BeanDefinitionRegistry的注册方法。BeanDefinitionRegistry是一个接口,有多个实现类,这里我们使用了默认的实现DefaultListableBeanFactory。3.8 DefaultListableBeanFactory.registerBeanDefinition代码啰嗦了一大堆,实际上所谓的注册,就是把beanName和beanDefinition对象作为键值对放到BeanFactory对象的beanDefinitionMap。但Spring经常把简单的逻辑写的非常“啰嗦”,仔细分析代码,发现他完成了几个事情:a. 对bean对象的校验b. 检查beanFactory中是否已经有同名的bean,如果有,进行相应处理c. 把bean对象放到beanDefinitionMap中(这就是最终所谓的注册)d. 清除整个过程缓存的对象数据以上便是Spring对bean解析注册的全过程,总结一下大致步骤:1. 加载XML文件,封装成Resource对象2. 调用Reader对象方法读取XML文件内容,并将相关属性放到BeanDefinition实例3. 将BeanDefinition对象放到BeanFactory对象
4. 实例化bean
&详细过程,预留位置
阅读(8974)
&re: Spring源码学习-bean加载& 11:36&
这个不错&&&&&&
&re: Spring源码学习-bean加载& 11:17&
不错,调试看下,基本按上述流程&&&&&&
&re: Spring源码学习-bean加载& 11:09&
详细过程,预留位置?2年了 哦
亲,说我博客名字,给你们打折!

我要回帖

更多关于 怎么导入spring源码 的文章

 

随机推荐