`

spring 加载bean过程源码简易解剖

阅读更多
这一篇主要是讲用载入bean的过程。其实就是IOC.低调 低调。。

我把重要的都挑出来了。一步步往下看就明白spring载入bean.xml里面bean的原理 。
感觉像候杰的 MFC深入浅出,哈哈。

观看规则

接下 表示下一层代码。
接上 表示最近上面要调用的代码的详细部分。




public class XmlBeanFactory extends DefaultListableBeanFactory {

        //新建一个bean分析器,把this注册到里面是因为,在分析器解析好一个bean时,可以立即用这个this里的注册方法去保存bean,往下看就明白。任何bean到最后都是保存在XmlBeanFactory里的(其实是DefaultListableBeanFactory)。 

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {

		super(parentBeanFactory);
                //载入xml文件
		this.reader.loadBeanDefinitions(resource); //往下->
	}
}

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
     //接上
     public int loadBeanDefinitions(Resource resource) throws BeansException {

		InputStream is = null;

		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

		factory.setValidating(this.validating);

		DocumentBuilder docBuilder = factory.newDocumentBuilder();

		docBuilder.setErrorHandler(this.errorHandler);

		if (this.entityResolver != null) {
		    docBuilder.setEntityResolver(this.entityResolver);
		}
		is = resource.getInputStream();
//用Xerces解析xml,生成dom
		Document doc = docBuilder.parse(is);
//registerBeanDefinitions分析dom
		return registerBeanDefinitions(doc, resource); //往下

	}

//接上
        public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {

		XmlBeanDefinitionParser parser = (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
//这个parserClass 是  DefaultXmlBeanDefinitionParser.class
		return parser.registerBeanDefinitions(this, doc, resource); //往下->

	}

}

public class DefaultXmlBeanDefinitionParser implements XmlBeanDefinitionParser {
//明显就是bean.xml里面出现的很熟悉的标签,说明已经快到底层类了
       

	public static final String AUTOWIRE_BY_NAME_VALUE = "byName";
	public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";
	public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";
	public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";
	public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";
	public static final String NAME_ATTRIBUTE = "name";
	public static final String ALIAS_ATTRIBUTE = "alias";
	public static final String BEAN_ELEMENT = "bean";
	public static final String ID_ATTRIBUTE = "id";
	public static final String PARENT_ATTRIBUTE = "parent";
	public static final String CLASS_ATTRIBUTE = "class";
	public static final String SINGLETON_ATTRIBUTE = "singleton";
	public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";
	public static final String AUTOWIRE_ATTRIBUTE = "autowire";
	//...
   //接上
   public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource) throws BeanDefinitionStoreException {

		this.beanDefinitionReader = reader;
		this.resource = resource;;
		Element root = doc.getDocumentElement();
		//...

//这里准备开始正式解析bean
		int beanDefinitionCount = parseBeanDefinitions(root);//往下->
//这个beanDefinitionCount 就是解析出了多少个<bean></bean>
		
//...
		return beanDefinitionCount;
	}

protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
//Xerces开始循环找<bean>标签
		NodeList nl = root.getChildNodes();
		int beanDefinitionCounter = 0;
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element) {
				Element ele = (Element) node;
				if // ...
//..
				else if (BEAN_ELEMENT.equals(node.getNodeName())) {//这里是重点,开始解析bean
					beanDefinitionCounter++;
//分两步走,看下面详解。1.先把bean放到BeanDefinitionHolder
					BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele);//往下 1.->
//2.然后XmlBeanFactory去注册
					BeanDefinitionReaderUtils.registerBeanDefinition(
							bdHolder, this.beanDefinitionReader.getBeanFactory()); //往下 2. ->
				}
			}
		}
		return beanDefinitionCounter;
	}

//接上1. 哈哈,下面是第一步,是正常解析bean,在同一个类中
protected BeanDefinitionHolder parseBeanDefinitionElement(Element ele) throws BeanDefinitionStoreException {
		//...
                //下面可以看到其实最底层的解析bean在同一个类的parseBeanDefinitionElement方法里。因为spring把bean封装成BeanDefinition 再把BeanDefinition 封装成BeanDefinitionHolder 

		BeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName);//往下

//...
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}

//接上 , 这个方法很长,毕竟<bean>里attribute很多。
  protected BeanDefinition parseBeanDefinitionElement(Element ele, String beanName) throws BeanDefinitionStoreException {
		try {
                        //下面解析<bean>里的<property>,这个我不分析了。
			MutablePropertyValues pvs = parsePropertyElements(ele, beanName);
                        //将BeanDefinition封装成AbstractBeanDefinition 
			AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(
					className, parent, cargs, pvs, this.beanDefinitionReader.getBeanClassLoader());
			//...		
			return bd;
		}
		catch (/*...*/)
                   //...

		}
	}


}
//bean解析部分到此结束。。。。


//接上2. 这里是第二部,注册部分,回到上面注释里的分两部走这里。
public class BeanDefinitionReaderUtils {
  public static void registerBeanDefinition(
			BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory) throws BeansException {

		
//beanFactory就是XmlBeanFactory,其实是它的父类 DefaultListableBeanFactory在执行registerBeanDefinition


		beanFactory.registerBeanDefinition(bdHolder.getBeanName(), bdHolder.getBeanDefinition()); //往下
//...
	}

}

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
  
	/** Whether to allow re-registration of a different definition with the same name */
	private boolean allowBeanDefinitionOverriding = true;

	/** Map of bean definition objects, keyed by bean name */
//下面是真正藏bean的地方,其实是个Map,跟我预想的一样。
	private final Map beanDefinitionMap = new HashMap();
//下面List可能是给bean的名字做个索引,这是我的初步猜想。
	/** List of bean definition names, in registration order */
	private final List beanDefinitionNames = new ArrayList();
  //接上
  public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
//...
  Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
//根据allowBeanDefinitionOverriding这个变量来决定在bean.xml里的bean万一有同名的情况下否覆盖,因为allowBeanDefinitionOverriding默认是true,所以覆盖。
			if (!this.allowBeanDefinitionOverriding) {
				throw new BeanDefinitionStoreException(...);
			}
			else {
				//...只用注释提醒相同bean将要被覆盖了
			}
		}
		else {
                        //索引List里加上这个bean名字
			this.beanDefinitionNames.add(beanName);
		}
                //将bean藏在map里。用名字来索引。
		this.beanDefinitionMap.put(beanName, beanDefinition);
		
	}
//...

}
//结束



可以看到其实spring就是把bean.xml解析到一个map里。
至于获取bean的方法 ,我不用说大家都知道了,到了底层就是 map.get("bean name");
万流归终啊。。。。
over
分享到:
评论
1 楼 jwx0925 2010-10-27  
不错~自己再慢慢看看~

相关推荐

    dubbo源码解析2

    - **6.2.2.3 Main**:主入口,初始化Spring容器并加载所有的bean。 ##### 6.3 Extension机制 - **6.3.1 JavaSPI**:SPI(Service Provider Interface)是一种服务提供者接口机制,允许第三方扩展实现。 - **6.3.2...

    dubbo源码解析

    6. 在核心机制分析环节中,涉及了dubbo中的设计模式、Bean加载机制、Spring可扩展Schema、代理、远程调用流程、集群容错等关键内容。这些是dubbo框架中最为核心的实现部分,对于理解dubbo的工作原理至关重要。 7. ...

    Lucene+compass+spring+jdbc+庖丁的一个例子

    在这里,Spring可能被用来管理搜索服务的bean,以及协调与其他服务(如JDBC)的交互。 4. **JDBC (Java Database Connectivity)**: JDBC是Java语言访问数据库的标准API,它允许Java程序与各种数据库进行交互。在这...

    ldap与Acegi? ----Acegi配置文件解剖

    &lt;bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"&gt; ,dc=com" /&gt; ,dc=mycompany,dc=com" /&gt; &lt;/bean&gt; ``` 此部分配置了 LDAP 服务器的URL、基础DN以及管理员的凭证。...

    稳压罐sw16_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    稳压罐sw16_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    基于递推最小二乘法的永磁同步电机参数辨识及其MATLAB仿真

    内容概要:本文详细介绍了利用递推最小二乘法(RLS)进行永磁同步电机参数辨识的方法及其MATLAB仿真过程。首先解释了RLS算法的优势,如不需要概率模型、计算量适中以及适用于嵌入式系统的实时参数更新。接着展示了将电机电压方程转换为标准形式Y=φθ的具体步骤,并提供了核心的RLS迭代代码。文中还讨论了仿真过程中的一些关键技术细节,如遗忘因子的选择、协方差矩阵的初始化和更新方式、电流信号的处理方法等。最终给出了仿真结果,显示电阻和电感的辨识误差分别达到了0.08%和0.12%,并指出了实际应用中需要注意的数据同步和数值稳定性问题。 适合人群:从事电机控制研究的技术人员、研究生及以上学历的学生。 使用场景及目标:①帮助研究人员理解和掌握RLS算法在电机参数辨识中的应用;②提供详细的仿真代码和配置建议,便于快速搭建实验环境;③指导如何优化算法性能,提高参数辨识精度。 其他说明:本文不仅涵盖了理论推导,还包括了大量的实践经验分享和技术细节探讨,有助于读者全面理解RLS算法的实际应用。同时,文中提到的仿真方案可以方便地移植到DSP平台,进一步扩展了其实用价值。

    零起点Python大数据与量化交易

    零起点Python大数据与量化交易

    管道清污机器人sw16可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    管道清污机器人sw16可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    电路仿真:数字电路仿真.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    电能质量分析:电压暂降与中断分析.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    thai-scalable-garuda-fonts-0.6.5-1.el8.x64-86.rpm.tar.gz

    1、文件说明: Centos8操作系统thai-scalable-garuda-fonts-0.6.5-1.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf thai-scalable-garuda-fonts-0.6.5-1.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm

    基于ABAQUS的滑坡与沉降对埋地管道影响的有限元分析及应用

    内容概要:本文详细介绍了利用ABAQUS进行滑坡和沉降对埋地管道影响的有限元分析方法。主要内容涵盖了几何建模、材料属性定义、接触设置、边界条件与加载等方面的技术细节。通过具体的Python脚本示例展示了如何构建模型,并深入探讨了滑坡和沉降条件下管道的应力、应变分布及其潜在破坏机制。此外,还分享了一些实战经验和优化技巧,如材料模型选择、接触条件设置、边界条件处理等,强调了这些因素对结果准确性的重要影响。 适合人群:从事地下管道工程设计、施工及维护的专业技术人员,尤其是那些希望深入了解滑坡和沉降对管道影响的研究人员和技术专家。 使用场景及目标:适用于评估和预测滑坡和沉降对埋地管道造成的力学响应,帮助工程师们更好地理解和应对复杂的地质灾害环境,从而提高管道系统的安全性与稳定性。 其他说明:文中提供的Python代码片段仅为示意,具体实施时需结合ABAQUS的实际接口和项目需求进行适当调整。同时,对于大规模模型的计算,建议使用高性能计算资源以确保效率和精度。

    Java实习一天高频面试突击!最常见的几种面试题型!!!

    Java一天面试突击,迅速掌握Java常见面试题

    莲子去壳机设计模型SW10_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    莲子去壳机设计模型SW10_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    MFRC-522+RC522+RFID射频+IC卡感应模块

    MFRC-522+RC522+RFID射频+IC卡感应模块

    学术研究学术研究提示设计50招:从论文撰写到润色降重的全方位指南学术研究中常见的

    内容概要:《学术研究提示设计 50 招》是一份详尽的指南,旨在帮助研究人员提高学术写作和研究效率。该文档涵盖了从论文撰写、润色、翻译、查重降重、参考文献管理、投稿审稿到文献阅读等多个方面的具体操作指令。每一章节均针对特定任务提供了详细的步骤和注意事项,例如如何撰写标题、摘要、致谢,如何进行英文润色、中英翻译,以及如何优化逻辑结构等。文档还介绍了如何利用AI工具进行文献分析、术语表提取和研究方向探索等内容,为研究者提供了全面的支持。 适合人群:适用于学术研究人员,特别是那些需要撰写、润色和提交学术论文的研究者,包括研究生、博士生及高校教师等。 使用场景及目标:① 提供一系列具体的指令,帮助研究者高效完成论文的各个部分,如撰写标题、摘要、致谢等;② 提供润色和翻译的详细指导,确保论文语言的准确性和专业性;③ 提供查重降重的方法,确保论文的原创性;④ 提供参考文献管理和投稿审稿的指导,帮助研究者顺利发表论文;⑤ 利用AI工具进行文献分析、术语表提取和研究方向探索,提高研究效率。 阅读建议:此资源不仅提供了具体的指令和方法,更重要的是引导研究者如何思考和解决问题。因此,在学习过程中,不仅要关注具体的步骤,还要理解背后的原理和逻辑,结合实际案例进行实践和反思。

    项目optionc-20250409

    项目optionc-20250409

    2023年c语言程序设计基本概念考点归纳.doc

    2023年c语言程序设计基本概念考点归纳.doc

    电能质量仿真:谐波分析与仿真.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    基于Matlab的模拟与数字滤波器设计:IIR、FIR及经典滤波器类型的实战详解

    内容概要:本文详细介绍了使用Matlab进行模拟和数字滤波器设计的方法,涵盖了巴特沃斯、切比雪夫等多种经典滤波器类型。首先讲解了模拟滤波器的设计,如巴特沃斯滤波器的通带平坦性和切比雪夫滤波器的通带波纹特性,并提供了具体的代码示例。接着讨论了数字滤波器的设计,包括IIR滤波器的递归特性和FIR滤波器的线性相位特性,同样附有详细的代码实现。文中还特别强调了不同类型滤波器之间的转换方法以及设计过程中常见的注意事项,如频率归一化、阶数选择等。最后推荐了一些实用的Matlab工具,如fvtool和FDATool,帮助用户更直观地理解和调试滤波器设计。 适合人群:具有一定信号处理基础和技术背景的研究人员、工程师及学生。 使用场景及目标:适用于需要进行滤波器设计的实际工程应用,如通信系统、音频处理等领域。目标是让读者掌握滤波器设计的基本原理和具体实现方法,能够独立完成滤波器的设计和调试。 其他说明:文章不仅提供了理论知识,还通过大量实例代码帮助读者更好地理解和应用所学内容。建议读者在实践中多尝试不同的参数配置,以加深对滤波器特性的理解。

Global site tag (gtag.js) - Google Analytics