spring IOC源码分析(2)
refresh这个方法包含了整个BeanFactory初始化的过程,定位资源由obtainFreshBeanFactory()来完成,
- protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
- refreshBeanFactory();
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- if (logger.isDebugEnabled()) {
- logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
- }
- return beanFactory;
- }
可以看到其调用了refreshBeanFactory(),refreshBeanFactory()在这个类中是抽象方法,其实现在AbstractRefreshableApplicationContext中。
- protected final void refreshBeanFactory() throws BeansException {
- if (hasBeanFactory()) {
- destroyBeans();
- closeBeanFactory();
- }
- try {
- DefaultListableBeanFactory beanFactory = createBeanFactory();
- beanFactory.setSerializationId(getId());
- customizeBeanFactory(beanFactory);
- loadBeanDefinitions(beanFactory);
- synchronized (this.beanFactoryMonitor) {
- this.beanFactory = beanFactory;
- }
- }
- catch (IOException ex) {
- ……
- }
- }
在这个方法中,先判断BeanFactory是否存在,如果存在则先销毁beans并关闭beanFactory,接着创建DefaultListableBeanFactory,并调用loadBeanDefinitions(beanFactory)装载bean定义。loadBeanDefinitions方法同样是抽象方法,是由其子类实现的,也即在AbstractXmlApplicationContext中。
- protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
- <span style="color:#33ff33;"> // 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件</span>
- XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
- <span style="color:#33ff33;">//这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的</span>
- <span style="color:#33ff33;"> //因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader </span>
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
- initBeanDefinitionReader(beanDefinitionReader);
- <span style="color:#33ff33;">//这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理</span>
- loadBeanDefinitions(beanDefinitionReader);
- }
接着我们转到beanDefinitionReader中进行处理
- protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
- Resource[] configResources = getConfigResources();
- if (configResources != null) {
- <span style="color:#33ff33;"> //调用XmlBeanDefinitionReader来载入bean定义信息。</span>
- reader.loadBeanDefinitions(configResources);
- }
- String[] configLocations = getConfigLocations();
- if (configLocations != null) {
- reader.loadBeanDefinitions(configLocations);
- }
- }
可以到org.springframework.beans.factory.support看一下BeanDefinitionReader的结构

在其抽象父类AbstractBeanDefinitionReader中定义了载入过程
- public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
- <span style="color:#33ff33;"> //这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader </span>
- ResourceLoader resourceLoader = getResourceLoader();
- <span style="color:#33ff33;">//如果没有找到我们需要的ResourceLoader,直接抛出异常</span>
- if (resourceLoader instanceof ResourcePatternResolver) {
- <span style="color:#33ff33;">// 这里处理我们在定义位置时使用的各种pattern,需要 ResourcePatternResolver来完成</span>
- try {
- Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
- int loadCount = loadBeanDefinitions(resources);
- return loadCount;
- }
- ........
- }
- else {
- <span style="color:#33ff33;">// 这里通过ResourceLoader来完成位置定位</span>
- Resource resource = resourceLoader.getResource(location);
- <span style="color:#33ff33;"> // 这里已经把一个位置定义转化为Resource接口,可以供XmlBeanDefinitionReader来使用了</span>
- int loadCount = loadBeanDefinitions(resource);
- return loadCount;
- }
- }


看到第8、16行,结合上面的ResourceLoader与ApplicationContext的继承关系图,可以知道此时调用的是DefaultResourceLoader中的getSource()方法定位Resource,因为ClassPathXmlApplicationContext本身就是DefaultResourceLoader的实现类,所以此时又回到了ClassPathXmlApplicationContext中来。
继续回到XmlBeanDefinitionReader的loadBeanDefinitions(Resource …)方法看得到代表bean文件的资源定义以后的载入过程。
- public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
- .......
- try {
- <span style="color:#33ff33;">//这里通过Resource得到InputStream的IO流</span>
- InputStream inputStream = encodedResource.getResource().getInputStream();
- try {
- <span style="color:#33ff33;"> //从InputStream中得到XML的解析源</span>
- InputSource inputSource = new InputSource(inputStream);
- if (encodedResource.getEncoding() != null) {
- inputSource.setEncoding(encodedResource.getEncoding());
- }
- <span style="color:#33ff33;">//这里是具体的解析和注册过程</span>
- return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
- }
- finally {
- <span style="BACKGROUND-COLOR: #33ff33">//关闭从Resource中得到的IO流</span>
- inputStream.close();
- }
- }
- .........
- }
- protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
- throws BeanDefinitionStoreException {
- try {
- int validationMode = getValidationModeForResource(resource);
- <span style="color:#33ff33;">//通过解析得到DOM,然后完成bean在IOC容器中的注册</span>
- Document doc = this.documentLoader.loadDocument(
- inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);
- return registerBeanDefinitions(doc, resource);
- }
- .......
- }
在doLoadBeanDefinitions(…)先把定义文件解析为DOM对象,然后进行具体的注册过程。
- public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
- <span style="color:#33ff33;">//具体的注册过程,首先得到XmlBeanDefinitionDocumentReader来处理xml的bean定义文件</span>
- BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
- documentReader.setEnvironment(this.getEnvironment());
- int countBefore = getRegistry().getBeanDefinitionCount();
- <span style="color:#33ff33;">//调用注册方法</span>
- documentReader.registerBeanDefinitions(doc,createReaderContext(resource));
- return getRegistry().getBeanDefinitionCount() - countBefore;
- }
- <p> </p>
具体的过程在BeanDefinitionDocumentReader中完成,在DefaultBeanDefinitionDocumentReader的方法中完成bean定义文件的解析和IOC容器中bean的初始化。
- public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
- this.readerContext = readerContext;
- logger.debug("Loading bean definitions");
- Element root = doc.getDocumentElement();
- doRegisterBeanDefinitions(root);
- }
- protected void doRegisterBeanDefinitions(Element root) {
- <span style="color:#33ff33;">……(注:省略号表示省略掉了代码)
- //通过代理delegate解析</span>
- BeanDefinitionParserDelegate parent = this.delegate;
- this.delegate = createHelper(readerContext, root, parent);
- preProcessXml(root);
- parseBeanDefinitions(root, this.delegate);
- postProcessXml(root);
- this.delegate = parent;
- }
- protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
- if (delegate.isDefaultNamespace(root)) {
- <span style="color:#33ff33;">//得到xml文件的子节点,比如各个bean节点</span>
- NodeList nl = root.getChildNodes();
- <span style="color:#33ff33;">//对每个节点进行分析处理</span>
- for (int i = 0; i < nl.getLength(); i++) {
- Node node = nl.item(i);
- if (node instanceof Element) {
- Element ele = (Element) node;
- if (delegate.isDefaultNamespace(ele)) {
- <span style="color:#33ff33;">//这里是解析过程的调用,对缺省的元素进行分析比如bean元素</span>
- parseDefaultElement(ele, delegate);
- }
- else {
- delegate.parseCustomElement(ele);
- }
- }
- }
- }
- else {
- delegate.parseCustomElement(root);
- }
- }
- private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
- <span style="color:#33ff33;">//对元素Import进行处理</span>
- if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
- importBeanDefinitionResource(ele);
- }
- else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
- processAliasRegistration(ele);
- }
- <span style="color:#33ff33;">//对我们熟悉的bean元素进行处理</span>
- else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
- processBeanDefinition(ele, delegate);
- }
- else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
- <span style="color:#33ff33;">// recurse</span>
- doRegisterBeanDefinitions(ele);
- }
- }
- protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
- <span style="color:#33ff33;">//委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包括了具体的bean解析过程。把解析bean文件得到的信息放在BeanDefinition里,它是bean信息的主要载体,也是IOC容器的管理对象。</span>
- BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
- if (bdHolder != null) {
- bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
- try {
- <span style="color:#33ff33;">// Register the final decorated instance.
- //向IOC容器注册,实际是放到IOC容器的一个map里</span>
- BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
- }
- catch (BeanDefinitionStoreException ex) {
- ……
- }
- <span style="color:#33ff33;">// Send registration event.
- //这里向IOC容器发送事件,表示解析和注册完成</span>
- getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
- }
可以看到在processBeanDefinition中对具体bean元素的解析是交给BeanDefinitionParserDelegate来完成的。我们接着看其实现的函数:
- public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
- <span style="color:#33ff33;">……(省略)</span>
- AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
- if (beanDefinition != null) {
- <span style="color:#33ff33;">//BeanDefinition解析过程</span>
- ……(省略)
- String[] aliasesArray = StringUtils.toStringArray(aliases);
- <span style="color:#33ff33;">//将解析完的bean定义包装后返回</span>
- return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
- }
- return null;
- }
- <p> </p>
在这里对定义文件中的bean元素进行解析,得到AbstractBeanDefinition,并用BeanDefinitionHolder封装后返回。
下面我们看解析完的bean如何在IOC容器中注册:在BeanDefinitionReaderUtils中调用的是:
- public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
- throws BeanDefinitionStoreException {
- <span style="color:#33ff33;">// Register bean definition under primary name.
- //得到需要注册bean的名字</span>
- String beanName = definitionHolder.getBeanName();
- <span style="color:#33ff33;">//调用IOC来注册bean的过程,需要得到BeanDefinition</span>
- registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
- <span style="color:#33ff33;">// Register aliases for bean name, if any.
- //将别名通过IOC容器和bean联系起来进行注册</span>
- String[] aliases = definitionHolder.getAliases();
- if (aliases != null) {
- for (String aliase : aliases) {
- registry.registerAlias(beanName, aliase);
- }
- }
- }
接着我们看看bean的注册实现,从上面看到其调用的是BeanDefinitionRegistry的方法registerBeanDefinition完成注册,跟踪代码可知BeanFactory容器的一个实现DefaultListableBeanFactory实现了这个接口并提供了注册的具体实现:

- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {
- ......
- if (beanDefinition instanceof AbstractBeanDefinition) {
- try {
- ((AbstractBeanDefinition) beanDefinition).validate();
- }
- catch (BeanDefinitionValidationException ex) {
- <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span>
- ……
- }
- }
- synchronized (this.beanDefinitionMap) {
- Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
- if (oldBeanDefinition != null) {
- if (!this.allowBeanDefinitionOverriding) {
- <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span>
- ……
- }
- else {
- if (this.logger.isInfoEnabled()) {
- ……
- }
- }
- }
- else {
- this.beanDefinitionNames.add(beanName);
- this.frozenBeanDefinitionNames = null;
- }
- this.beanDefinitionMap.put(beanName, beanDefinition);
- resetBeanDefinition(beanName);
- }
- }
可以看到整个注册过程很简单,就是将bean添加到BeanDefinition的map中。这样就完成了bean定义在IOC容器中的注册,就可被IOC容器进行管理和使用了。
spring IOC源码分析(2)的更多相关文章
- Spring IOC 源码分析
Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...
- spring IoC源码分析 (3)Resource解析
引自 spring IoC源码分析 (3)Resource解析 定义好了Resource之后,看到XmlFactoryBean的构造函数 public XmlBeanFactory(Resource ...
- Spring IoC 源码分析 (基于注解) 之 包扫描
在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...
- Spring Ioc源码分析系列--Ioc的基础知识准备
Spring Ioc源码分析系列--Ioc的基础知识准备 本系列文章代码基于Spring Framework 5.2.x Ioc的概念 在Spring里,Ioc的定义为The IoC Containe ...
- Spring Ioc源码分析系列--前言
Spring Ioc源码分析系列--前言 为什么要写这个系列文章 首先这是我个人很久之前的一个计划,拖了很久没有实施,现在算是填坑了.其次,作为一个Java开发者,Spring是绕不开的课题.在Spr ...
- Spring Ioc源码分析系列--Ioc源码入口分析
Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...
- Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析
Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析 前言 上一篇文章Spring Ioc源码分析系列--Ioc源码入口分析已经介绍到Ioc容器 ...
- Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理
Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...
- Spring Ioc源码分析系列--Bean实例化过程(一)
Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...
- Spring Ioc源码分析系列--Bean实例化过程(二)
Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...
随机推荐
- Overview & Change Log
Overview & Change Log Nova Framework is a PHP 5.5+ MVC Framework. It's designed to be lightweigh ...
- UITableView优化那点事
forkingdog关于UITableView优化的框架其实已经能够应用在一般的场景,且有蛮多的知识点供我们借鉴,借此站在巨人的肩膀上来分析一把. 至于UITableView的瓶颈在哪里,我相信网上随 ...
- myeclipse安装本地maven fastdfs_client.jar
为了方便应用程序的访问FastDFS,官网提供了fastdfs-client-java,以便更好的与应用程序结合使用. 下载fastdfs-client-java源码添加到项目工程里面,添加配置文件: ...
- 电脑小白学习软件开发-C#语言基础之循环重点讲解,习题
写代码也要读书,爱全栈,更爱生活.每日更新原创IT编程技术及日常实用视频. 我们的目标是:玩得转服务器Web开发,搞得懂移动端,电脑客户端更是不在话下. 本教程是基础教程,适合任何有志于学习软件开发的 ...
- OAuth2集成——《跟我学Shiro》
http://jinnianshilongnian.iteye.com/blog/2038646 目前很多开放平台如新浪微博开放平台都在使用提供开放API接口供开发者使用,随之带来了第三方应用要到开放 ...
- SQL-学习使用FOR XML PATH
前言:本人SQL技术很烂,然后工作时间也不久,许多东西都还在学习中,说的不好的地方尽请谅解. 首先跟大家说一下我今天遇到的问题吧. 查出的数据有三列,第一列存放的是32位的GUID,Res_Name存 ...
- Objective-C 学习笔记(Day 1)
-------------------------------------------- Hello World //引入头文件 //c中的引入头文件的方式 //#include <stdio. ...
- Eclipse恢复初始界面&打开视图
恢复初始界面: 单击菜单栏的windows主菜单,在子菜单里选择 Reset Perspective 会弹出各对话框 ,点 ok就可以了 打开视图:Windows->Show View 其中Ot ...
- JAVA笛卡尔曲线
效果图如下: import java.applet.*; import java.awt.*; public class Descartes extends Applet { int AppletWi ...
- NOIP(提高组)DAY1国王游戏
问题描述 恰逢H国国庆,国王邀请n位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这n位大臣排成一排,国王站在队伍的最前面.排好队 ...