最近用spring的时候感觉不怎么了解内部原理,用起来有些不习惯,于是找空看了一下spring的源码,看了一下bean加载的流程以及调用流程,现总结如下:
加载
contextLoaderListener->ContextLoader.initWebApplicationContext,调用本对象的createWebApplicationContext->ConfigurableWebApplicationContext.refresh()->AbstractApplicationContext.refresh();
在上面的refresh里面有
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
追踪这段代码,发现调用了:AbstractRefreshableApplicationContext的以下方法:
protected final void refreshBeanFactory()
throws BeansException
{
if(hasBeanFactory())
{
destroyBeans();
closeBeanFactory();
}
try
{
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized(beanFactoryMonitor)
{
this.beanFactory = beanFactory;
}
}
catch(IOException ex)
{
throw new ApplicationContextException((new StringBuilder("I/O error parsing bean definition source for ")).append(getDisplayName()).toString(), ex);
}
}
这个方法里面有一句很重要: loadBeanDefinitions(beanFactory);
这一句的作用是从配置文件加载所有的BeanDefinition.
项目中用到的是基于xml的spring配置方式,所以最终的工厂类是:XmlWebApplicationContext。
加载beandefinition时,把逐个文件用XmlBeanDefinitionReader进行解析并加载bean。
XmlBeanDefinitionReader首先把每个配置文件载入成一个w3c的Document对象,然后 用 BeanDefinitionDocumentReader解析Document.
BeanDefinitionDocumentReader的实现类是DefaultBeanDefinitionDocumentReader。
实现类加载bean的方法如下:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
{
if(delegate.isDefaultNamespace(delegate.getNamespaceURI(root)))
{
NodeList nl = root.getChildNodes();
for(int i = 0; i < nl.getLength(); i++)
{
org.w3c.dom.Node node = nl.item(i);
if(node instanceof Element)
{
Element ele = (Element)node;
String namespaceUri = delegate.getNamespaceURI(ele);
if(delegate.isDefaultNamespace(namespaceUri))
parseDefaultElement(ele, delegate);
else
delegate.parseCustomElement(ele);
}
}
} else
{
delegate.parseCustomElement(root);
}
}
方法中的Element对象root其实就是之前的Document,是一个顶级的Element。
然后再通过BeanDefinitionParserDelegate解析这个root下面的每个Element,看看是不是下级Element,如果是,
判断Element是不是默认namespace(比如:beans-这个是默认,security,aop等),如果是:
调用parseDefaultElement(ele, delegate);否则调用delegate.parseCustomElement(ele)。
BeanDefinitionParserDelegate是一个很核心的类,这个类完成对bean对应的element的构造函数,bean参数,
bean的fields的解析并且分别进行保存,之后生成bean的实例的时候需要从中取出这些信息来生成bean实例。
parseCustomElemen方法的主要作用就是根据namespace调用对用的Namespacehandler解析element并且做 相应的操作(比如:securitynamespacehandler的作用是为应用根据security配置文件添加相应的filter).现在主要集中 在parseDefaultElement 方法上面,这个方法是提取bean的关键方法。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
{
if(delegate.nodeNameEquals(ele, "import"))
importBeanDefinitionResource(ele);
else
if(delegate.nodeNameEquals(ele, "alias"))
processAliasRegistration(ele);
else
if(delegate.nodeNameEquals(ele, "bean"))
processBeanDefinition(ele, delegate);
}
对于在默认namespace下面的常用标签:import,alias,bean,上面的方法都做了处理。下面主要跟踪一下常用的bean的解析: processBeanDefinition。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
{
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if(bdHolder != null)
{
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try
{
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch(BeanDefinitionStoreException ex)
{
getReaderContext().error((new StringBuilder("Failed to register bean definition with name '")).append(bdHolder.getBeanName()).append("'").toString(), ele, ex);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
至此,真正执行bean解析工作的类出来了:BeanDefinitionParserDelegate 。此类解析Element并且返回一个
BeanDefinitionHolder 对象。然后通过
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
支持,把BeanDefinition注册到了beanfactory里面。下面的工作就是取出bean了。
bean的获取
一个常用的方式是通过ApplicationContext接口来获取bean。getBean(String name)的实现类是AbstractApplicationContext。追踪代码,最终发现bean的获取着落在AbstractBeanFactory的doGetBean方法上。继续跟踪,可以跟踪到:AbstractAutowireCapableBeanFactory的doCreateBean方法(对于Prototype的bean),此方法的作用是创建bean的实例。跟踪以上方法,发现是依靠InstantiationStrategy来实例化bean。
有两张策略来实例化bean: SimpleInstantiationStrategy,CglibSubclassingInstantiationStrategy。从名字上很容易看出,前者是不用代理的实例化,后者是通过cglib生成代理类对象的实例化。
至此,bean的取出过程也大概清楚了。因为时间仓促,很多细节来不及描述,等有空了补全这篇文章。
分享到:
相关推荐
Spring 源码分析 Spring 框架是 Java 语言中最流行的开源框架之一,它提供了一个强大且灵活的基础设施来构建企业级应用程序。在 Spring 框架中,IOC 容器扮演着核心角色,本文将深入分析 Spring 源码,了解 IOC ...
本压缩包“Spring源码解析”提供了对Spring框架核心组件——IOC(Inversion of Control,控制反转)、AOP(Aspect Oriented Programming,面向切面编程)以及Transaction(事务管理)的源码分析,帮助开发者更全面地...
### Spring源码解析知识点 #### 一、Spring IoC 容器详解 ##### 1. BeanFactory —— 最基础的IoC容器 - **概念**:`BeanFactory` 是Spring框架中最基本的IoC容器,它负责管理Bean的生命周期,包括创建、配置和...
Spring 源代码分析系列涵盖了多个关键模块,包括事务处理、IoC容器、JDBC、MVC、AOP以及与Hibernate和Acegi安全框架的集成。以下是对这些知识点的详细阐述: 1. **Spring 事务处理**:Spring 提供了声明式事务管理...
《Spring源码分析》 Spring框架作为Java领域中不可或缺的一部分,其强大之处在于它提供了丰富的功能,包括依赖注入(Dependency Injection,简称DI)、面向切面编程(Aspect-Oriented Programming,简称AOP)、事务...
spring源码分析专题,源码分析视频,对spring的源码进行分析
10. **源码分析**:深入阅读Spring的源码可以帮助理解其设计思想和实现机制,比如Bean的生命周期、AOP的代理过程、事件驱动模型等。 通过"spring源码解析"的学习,开发者可以更好地理解和利用Spring框架,提升开发...
Spring源码深度解析第二版 Spring是一款广泛应用于Java企业级应用程序的开源框架,旨在简化Java应用程序的开发和部署。Spring框架的核心主要包括了IoC容器、AOP、MVC框架等模块。 第1章 Spring整体架构和环境搭建 ...
6. **Spring源码分析**:通过阅读源码,理解Spring框架的工作原理,增强对框架的深入理解。 接下来,我们转向MyBatis,这是一个轻量级的持久层框架,它提供了灵活的SQL映射机制,使得数据库操作变得简单。"MyBatis3...
以上只是Spring源码分析的部分内容,实际源码中还包括Spring的其他模块,如Spring Batch(批处理)、Spring Security(安全)、Spring Integration(集成)等。理解并掌握Spring源码,有助于我们更好地利用Spring...
《Spring5 源码分析(第 2 版)》是某Tom老师精心编写的深度解析文档,旨在帮助读者全面理解Spring5的核心机制和设计理念。Spring作为Java领域最为广泛应用的框架之一,其源码的深入理解对于开发者来说至关重要。这篇...
本文将围绕Spring的核心概念和关键组件,通过源码分析,帮助你深入理解Spring的工作原理。 首先,Spring的核心是依赖注入(Dependency Injection,DI),它是控制反转(Inversion of Control,IoC)的一种实现方式...
总之,Spring源码分析是提升Java开发者技术水平的重要途径,它能够帮助我们更有效地利用Spring框架,优化代码,解决复杂问题,同时也能为面试做好充分准备。通过深入学习Spring的各个组成部分,我们可以成为更优秀的...
《Spring5 源码分析(第 2 版)》是针对Spring框架第五个主要版本的深度解析著作,由知名讲师倾心打造,旨在帮助读者深入理解Spring框架的内部工作机制,提升对Java企业级应用开发的专业技能。本书涵盖了Spring框架的...
spring源码分析,百度云视频。链接如果失效了,请私聊我。
在源码分析的过程中,读者会深入理解Spring的内部工作机制,例如如何解析配置、如何创建bean实例、如何实现AOP代理等。这将有助于开发者编写更高效、更健壮的代码,也能为参与Spring的扩展或定制打下坚实基础。 总...
本篇文档将对Spring框架的核心源码进行解析,以帮助开发者更深入地理解Spring的工作原理和核心概念。 首先,Spring框架通过使用IoC容器来管理应用对象的创建和依赖关系。这种做法可以让程序员从创建对象的复杂性中...
### Spring源码分析_Spring_IOC:深入理解Spring的IOC容器机制 #### 基本概念与核心作用 在探讨Spring框架的核心组件之一——IOC(Inversion of Control,控制反转)容器之前,首先需要理解它在Spring框架中的角色...