`
zddava
  • 浏览: 243704 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring源代码分析 -- IOC容器(一)

阅读更多
Spring是知道很久了,一直断断续续在看,不过用到它的机会不是很多,于是想阅读一下Spring的源代码来更深入的了解下这个框架(源代码的版本是2.5.6)。首先,当然是从Spring的IOC容器开始了,最基本的IOC容器就是org.springframework.beans.factory.BeanFactory了,这个接口定义了一个基本的IOC容器应该具有的行为,其源代码如下所示:

public interface BeanFactory {

	/** 通过在bean的名字前加上&可以返回生成Bean的FactoryBean本身 */
	String FACTORY_BEAN_PREFIX = "&";

	/** 根据名字返回Bean */
	Object getBean(String name) throws BeansException;

	/** 根据名字和类型返回Bean */
	Object getBean(String name, Class requiredType) throws BeansException;

	/** 用于使用静态方法工厂创建prototype的bean,args是给工厂方法的参数 */
	Object getBean(String name, Object[] args) throws BeansException;

	/** 查询IOC容器中是否有特定名字的Bean */
	boolean containsBean(String name);

	/** 判断Bean是不是单例的 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/** 判断Bean是不是原型的 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/** 判断名字为name的Bean的类型是否是targetType */
	boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;

	/** 返回Bean的类型 */
	Class getType(String name) throws NoSuchBeanDefinitionException;

	/** 判断Bean的所有别名,如果使用别名查询的,那么Bean的原始名字也会返回的 */
	String[] getAliases(String name);

}


BeanFactory是一切IOC容器类的基接口,它定义了IOC容器的基本行为,下面来看几个具体的实现类,首先从XmlBeanFactory开始。

public class XmlBeanFactory extends DefaultListableBeanFactory {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}

	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}

}


这个类的构造函数说明了配置文件的载入过程,就是通过XmlBeanDefinitionReader的#loadBeanDefinitions()方法来载入的,源代码如下:

	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}


它又进一步调用了#loadBeanDefinitions(EncodedResource)这个方法,它的源代码如下。

	public int loadBeanDefinitions(EncodedResource encodedResource)
			throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("Loading XML bean definitions from " + encodedResource.getResource());
		}

		Set currentResources = (Set) this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		// 如果Set中已经包含了这个资源,那么就不要重复载入
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException("Detected recursive loading of "
					+ encodedResource + " - check your import definitions!");
		}
		try {
			// 构建一个解析XML使用的InputStream对象
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				// 实做Bean定义的载入
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			} finally {
				inputStream.close();
			}
		} catch (IOException ex) {
			throw new BeanDefinitionStoreException("IOException parsing XML document from "
					+ encodedResource.getResource(), ex);
		} finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.set(null);
			}
		}
	}


这样,经过了一些列的处理,最后来到了实做载入的#doLoadBeanDefinitions()方法。

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			int validationMode = getValidationModeForResource(resource);

			// 通过InputSource来载入XML到一个Document对象
			Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(),
					this.errorHandler, validationMode, isNamespaceAware());
			// 注册Bean的定义
			return registerBeanDefinitions(doc, resource);
		} catch (BeanDefinitionStoreException ex) {
			throw ex;
		} catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line "
					+ ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		} catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		} catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		} catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		} catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}


下面首先来看一下这个Document的获取过程,这里documentLoader是一个org.springframework.beans.factory.xml.DefaultDocumentLoader类的对象,通过它的#loadDocument()方法可以获得一个Document对象,这个过程先不去仔细看,主要来看一下这个#registerBeanDefinitions()方法。

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// 支持老的XmlBeanDefinitionParser
		if (this.parserClass != null) {
			XmlBeanDefinitionParser parser = (XmlBeanDefinitionParser) BeanUtils
					.instantiateClass(this.parserClass);
			return parser.registerBeanDefinitions(this, doc, resource);
		}
		// 使用BeanDefinitionDocumentReader来载入
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 已经注册的Bean数量
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 注册Bean
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}


这里XmlBeanDefinitionParser的处理就不仔细看了,因为是Spring为了兼容老的实现而保留的,下边主要来看一下使用BeanDefinitionDocumentReader的处理过程。

首先就应该是BeanDefinitionDocumentReader的构造,就是#createBeanDefinitionDocumentReader()方法

	protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
		return (BeanDefinitionDocumentReader) BeanUtils.instantiateClass(this.documentReaderClass);
	}


这里的documentReaderClass这个变量的值为DefaultBeanDefinitionDocumentReader.class,也就是org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader,也就是BeanDefinitionDocumentReader的实现类。

下面来看看它的#registerBeanDefinitions()方法。

	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;

		logger.debug("Loading bean definitions");
		// 根元素
		Element root = doc.getDocumentElement();
		
		// 这个类很重要,主要是委托给它来实现解析
		BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);

		// 如果想自己实现Bean的注册过程,可以继承DefaultBeanDefinitionDocumentReader,
		// 然后覆盖#preProcessXml()和#postProcessXml()来完成更多的个性化实现。
		
		// 处理XML前,默认无行为
		preProcessXml(root);
		
		// 解析Bean的定义
		parseBeanDefinitions(root, delegate);
		
		// 处理XML后,默认无行为
		postProcessXml(root);
	}


这个方法有两个部分需要考虑下,一个是BeanDefinitionParserDelegate实例的构建,另外一个是#parseBeanDefinitions()方法。

首先来看一下BeanDefinitionParserDelegate的构建

	protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {
		BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
		delegate.initDefaults(root);
		return delegate;
	}


这里调用了BeanDefinitionParserDelegate的#initDefaults()方法来初始化,并把document的root元素作为参数传递了进去。这个方法主要是对一些全局属性的初始化,可以看看它的源代码:

	public void initDefaults(Element root) {
		DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
		// default-lazy-init -> 默认的延迟加载
		defaults.setLazyInit(root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE));
		// default-merge -> 对集合类的默认merge处理
		defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE));
		// default-autowire -> 默认的自动装配
		defaults.setAutowire(root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE));
		// default-dependency-check -> 默认的依赖检测
		defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
		// default-autowire-candidates -> 查找自动装配的Bean的样式
		if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
			defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
		}
		// default-init-method -> 默认初始化方法
		if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
			defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
		}
		// default-destroy-method -> 模式销毁方法
		if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
			defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
		}
		defaults.setSource(this.readerContext.extractSource(root));

		this.defaults = defaults;
		this.readerContext.fireDefaultsRegistered(defaults);
	}


这个方法提供了针对根标签<beans>的属性(xml定义的bean的一些默认行为)的载入。在这里会看到很多spring配置文件中出现过的身影。

看过了BeanDefinitionParserDelegate之后,下面就来看看#parseBeanDefinitions()方法的定义吧:

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					String namespaceUri = ele.getNamespaceURI();
					if (delegate.isDefaultNamespace(namespaceUri)) {
						// 解析默认的标签
						parseDefaultElement(ele, delegate);
					} else {
						// 解析不是在默认命名空间的
						delegate.parseCustomElement(ele);
					}
				}
			}
		} else {
			// 解析不是在默认命名空间的
			delegate.parseCustomElement(root);
		}
	}


下面是#parseDefaultElement()的定义:

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		// <import>的处理
		if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		// <alias>的处理
		else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		// <bean>的处理
		else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
	}


#parseDefaultElement()包含了<beans>标签的所有子标签的处理。

剩下的内容下次再说。:)

分享到:
评论

相关推荐

    Spring.net二----初探IOC容器.rar源代码

    Spring.Demo项目很可能是包含一个简单的Spring.NET应用示例,可能包括了XML配置文件、服务接口和实现类、以及如何使用IoC容器来获取和使用这些对象的代码。通过这个示例,你可以更直观地了解如何在实际项目中运用...

    Spring源代码解析(一):IOC容器.doc

    在Spring源代码解析的第一部分,我们将聚焦于IOC容器,特别是BeanFactory接口,它是所有Spring容器的基础。 BeanFactory接口是Spring的基石,它定义了基本的容器操作,如获取Bean、检查Bean是否存在、确定Bean的...

    Spring源码分析_Spring_IOC

    ### Spring源码分析_Spring_IOC:深入理解Spring的IOC容器机制 #### 基本概念与核心作用 在探讨Spring框架的核心组件之一——IOC(Inversion of Control,控制反转)容器之前,首先需要理解它在Spring框架中的角色...

    spring-demo10-注解-IOC.zip

    注解是Java语言提供的一种元数据机制,允许我们在源代码中嵌入信息,这些信息可以被编译器或者运行时环境解析和使用。Spring框架充分利用了这一特性,提供了一系列注解来简化配置,使得我们可以避免使用XML配置文件...

    Spring IOC容器实现分析.pdf 下载

    《Spring IOC容器实现分析》 在Java开发领域,Spring框架无疑是使用最为广泛的轻量级框架之一,其中的核心组件就是IOC(Inversion of Control)容器。本文将深入剖析Spring的IOC容器,理解其工作原理和重要功能,以...

    spring-context-3.2.0 spring-core-3.2.0 等齐全的Spring jar包

    这里提到的是一组完整的Spring库,包括`spring-core`、`spring-context`、`spring-webmvc`、`spring-web`、`spring-beans`、`spring-test`、`spring-jdbc`、`spring-orm`、`spring-aop`和`spring-tx`,它们都是3.2.0...

    spring-security-web源码所需jar包

    1. **spring-context-3.1.2.RELEASE.jar**:提供Spring的IoC(Inversion of Control)容器和AOP(Aspect Oriented Programming)支持,这是Spring框架的基础,为Spring Security提供了配置和事件处理能力。...

    spring-01-ioc1.rar

    2. **Spring容器**:Spring的核心是IoC容器,如BeanFactory和ApplicationContext,它们负责读取配置,实例化、配置及管理Bean。 3. **Bean定义**:如何在XML或Java配置中定义Bean,包括其类名、初始化方法、属性...

    Spring2.5.6源代码分析(一):IOC容器

    IoC容器是Spring框架的心脏,它负责管理对象的生命周期和依赖关系,使得开发者能够实现松耦合和高可测试性的应用程序。 首先,我们来理解什么是IoC。IoC,也被称为依赖注入(Dependency Injection),是一种设计...

    spring-framework-master

    例如,Spring的事件驱动模型、AOP的实现原理、以及IoC容器的内部工作流程等。此外,源码还展示了Spring如何与其他技术(如JDBC、JMS、EJB等)无缝集成,以及如何利用注解简化配置。 通过阅读和分析"spring-...

    springIOC核心组件分析.vsdx

    spring-context:上下文,即IOC容器 spring-context-support:对IOC的扩展,以及IOC子容器 spring-context-indexer:类管理组件和Classpath扫描 spring-expression:表达式语句 切面编程: spring-aop:面向切面编程,...

    Spring的IoC容器初始化源码解析

    ### Spring的IoC容器初始化源码解析 #### 一、Spring框架的核心——IoC容器 Spring框架是一个开源的轻量级Java开发框架,其核心功能是IoC(Inversion of Control,控制反转)容器和AOP(Aspect Oriented ...

    Spring-IoC 容器 - v1.01

    Spring支持多种持久化技术,如JDBC、Hibernate、MyBatis等,可以利用IoC容器管理这些DAO对象,使它们能够依赖于事务管理、数据源等服务。 **工厂模式** 工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳...

    Spring源码分析.pdf

    IOC容器是 Spring 框架的核心组件之一,它提供了一个统一的方式来管理应用程序中的对象。IOC 容器的主要功能是将对象的创建、管理和依赖关系解耦,使得应用程序更加灵活、可维护和可扩展。 在 Spring 中,IOC 容器...

    Spring源码解析4章150页+Spring3.2.4中文注释源码

    3、源码分析-IOC容器的初始化 4、源码分析-IOC容器的依赖注入 5、源码分析-IOC容器的高级特性 三阶段 Spring AOP的涉及原理及具体实践 SpringJDBC的涉及原理及二次开发 SpringMVC框架设计原理及手写实现 四阶段 ...

    官方原版源码spring-framework-5.1.4.RELEASE.zip

    首先,源码分析从`spring-framework-5.1.4.RELEASE-dist.zip`开始,这是Spring框架的基础组件包,包含了所有核心模块的类库和配置文件。主要模块有Core Container(核心容器)、Data Access/Integration(数据访问与...

    spring ioc容器部署实现

    #### 一、Spring IoC容器概述 Spring框架的核心特性之一就是Inversion of Control(IoC),也被称为Dependency Injection(DI)。IoC容器是Spring框架的重要组成部分,它负责管理对象的生命周期、配置和装配过程。...

    spring源码spring-framework-4.3.2.RELEASE

    1. **IoC(Inversion of Control)容器**:Spring的核心在于IoC容器,它负责管理对象的生命周期和依赖关系。在源码中,`BeanFactory`是IoC的基础接口,而`ApplicationContext`则提供了更高级的应用上下文功能。通过...

    官方原版源码spring-framework-5.2.3.RELEASE.zip

    IoC容器管理对象的生命周期和依赖关系,而AOP则实现了关注点分离,提高了代码的可维护性。在源码中,我们可以看到`org.springframework.beans`和`org.springframework.context`包是如何实现这些功能的。 `spring-...

    官方源码 spring-framework-5.3.2.zip

    Spring的IoC(Inversion of Control)容器和AOP(Aspect-Oriented Programming)支持在5.3.2中得到加强,包括对Java配置的优化,以及对注解的更精细控制。此外,还增强了Bean生命周期管理,如条件化 Bean 的创建和...

Global site tag (gtag.js) - Google Analytics