`

Spring的IOC源码解读&UML

阅读更多
<spring.version>4.0.6.RELEASE</spring.version>
这一部分主要记录bean定义的解析和加载,包括注解方式定义的bean。

【UML】
首先以uml展示ioc过程的全貌,为避免干扰,每个类仅表述了核心的属性,方法和方法内的关键代码。
refresh()方法标橙色,是外部调用的入口,如ContextLoaderListener。
标红色的是一些关键属性和实现。

uml连接:http://dl2.iteye.com/upload/attachment/0115/8766/bedf264c-a530-33b3-924a-2b1799eef3ac.png



【代码解读】
XmlWebApplicationContext继承了AbstractApplicationContext。AbstractApplicationContext的refresh()方法对外提供访问入口,定义了bean定义的解析,创建和一些过程处理,如aop等。使用方法模版的设计模式,由各子类实现一些过程的细节。

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
	}


在refresh()方法中,obtainFreshBeanFactory()方法负责beanFactory的创建及bean定义的解析逻辑,并让applicationContext持有beanFactory。

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}


refreshBeanFactory()是一个抽象方法,具体实现是由AbstractRefreshableApplicationContext实现的。在这个方法中,如果已经存在beanFactory,则销毁beanFactory持有的bean定义及bean实例,并销毁beanFactory,代码实现上就是附null。然后创建一个新的beanFactory,具体实现类为DefaultListableBeanFactory。

	@Override
	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) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}


loadBeanDefinitions()方法负责bean定义的解析,在AbstractRefreshableApplicationContext中是个抽象方法,由XmlWebApplicationContext实现。因为我们项目在web.xml配的是XmlWebApplicationContext。在这个方法中,会将beanFacotry以BeanDefinitionRegistry接口的实现放到XmlBeanDefinitionReader中,并让XmlBeanDefinitionReader持有beanFactory,以方便后面解析出beanDefinition后,可以注册到beanFactory中。当然实际持有beanFactory的是XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader,可以参看UML图。

	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}


根据在web.xml定义的contextConfigLocation,由XmlBeanDefinitionReader开始解析每个配置文件。整体流程的代码实现在XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader中。但bean定义的解析和加载在XmlBeanDefinitionReader中。

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			for (String configLocation : configLocations) {
				reader.loadBeanDefinitions(configLocation);
			}
		}
	}


实际的bean定义解析也不是由XmlBeanDefinitionReader完成的,XmlBeanDefinitionReader会创建DefaultBeanDefinitionDocumentReader,并将自己作为XmlReaderContext的一个属性,交由DefaultBeanDefinitionDocumentReader进行处理,并由DefaultBeanDefinitionDocumentReader持有XmlReaderContext。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException
		try {
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		documentReader.setEnvironment(this.getEnvironment());
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}


在DefaultBeanDefinitionDocumentReader解析bean定义的过程中,遇到非http://www.springframework.org/schema/beans命名空间的标签,会交由BeanDefinitionParserDelegate 进行解析。BeanDefinitionParserDelegate会持有DefaultBeanDefinitionDocumentReader的readerContext。

		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(this.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)) {
			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;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}


类似于注解和aop等的定义解析,都是由BeanDefinitionParserDelegate完成的,他会根据namespaceUri的不同,找到不同的NameSpaceHandler。查找的工作由readerContext持有的属性NamespaceHandlerResolver完成,对应的实现类是DefaultNamespaceHandlerResolver。而DefaultNamespaceHandlerResolver的创建,是在XMLBeanDefinitionReader在创建XmlReaderContext时,就已经指定的,可参考UML图,或者前面的代码解读。
NameSpaceHandler都放在DefaultNamespaceHandlerResolver的属性handlerMappings中,此处找到的实现类是NamespaceHandlerSupport。

	public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}


NamespaceHandlerSupport的属性parsers中存放了所需的BeanDefinitionParser。以注解为例,会找到ComponentScanBeanDefinitionParser,处理注解的bean定义解析,并最终调用readerContext的fireComponentRegistered方法,向eventListener注册componentDefinition。

	@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

		// Actually scan for bean definitions and register them.
		ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
		Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
		registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

		return null;
	}

	protected void registerComponents(
			XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

		Object source = readerContext.extractSource(element);
		CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

		for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
			compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
		}

		// Register annotation config processors, if necessary.
		boolean annotationConfig = true;
		if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
			annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
		}
		if (annotationConfig) {
			Set<BeanDefinitionHolder> processorDefinitions =
					AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
			for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
				compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
			}
		}

		readerContext.fireComponentRegistered(compositeDef);
	}


未完,待续 -=^^=-
  • 大小: 129.9 KB
分享到:
评论

相关推荐

    spring源码全部uml类图

    在"spring源码全部uml类图"中,我们可以深入探讨Spring框架的内部结构和设计模式。 首先,Spring框架的核心组件包括IoC(Inversion of Control,控制反转)容器和AOP(Aspect-Oriented Programming,面向切面编程)...

    spring源码UML图

    通过分析Spring的源码UML图,我们可以深入学习Spring的IoC容器、AOP、数据访问、事务管理等核心特性,并且能够提升我们的设计思维和软件建模能力。同时,这样的分析方式也能为我们在实际开发中应用Spring框架提供...

    Spring IOC架构介绍与源码分析(含插件开发)

    本课程通过UML结合源码进行全局的剖析了Spring_IOC容器的核心原理,以及插件的开发方法,以及插件实例(介绍SpingBoot和Spring定时器扩展原理)。通过本课程的学习您将对Spring_IOC整体架构有清晰的了解,知道5大核心...

    springboot2-spring5-studying:Springboot2,Spring源码学习项目,涉及SpringBoot2自动装配实现机制,Spring AOP动态代理以及IOC各种扩展接口的实现方式

    Spring AOP多种代理机制相关核心类介绍先介绍一些Spring Aop中一些核心类,大致分为三类: advisorCreator ,从spring ioc的扩展接口beanPostProcessor继承,主要用作扫描获取advisor。 advisor :顾问的意思,封装...

    java框架源码分析java框架源码分析

    例如,Spring框架中的IoC(Inversion of Control)容器是如何管理对象的生命周期,以及如何通过XML或注解配置实现依赖注入。此外,对于Spring MVC,我们可以分析DispatcherServlet如何分发请求到对应的控制器,以及...

    Java进阶教程Java设计模式(图解+框架源码分析+实战)视频教程

    学习spring框架是最好的提升的途径,spring框架将面向对象体现的淋漓尽致课程内容整个课程分为3大部分:第一部分是设计模式相关介绍设计模式的概述UML图软件设计原则第二部分是设计模式的学习(23种设计模式)创建者...

    资料-java设计模式(图解+框架源码分析+实战)

    * 自定义spring的IOC功能。 ### 5,适用人群 本课程定位是设计模式的入门课程,但是又聊了一下设计模式在spring中的使用。对于要从事高级工程师及架构师工作,设计模式、数据结构和算法是必须要求灵活运用的,所以...

    需求规格说明书1.2老师评审1

    6. **编写目的**:文档的编写旨在基于Blade开源项目源码和资料,结合软件工程实践、UML建模技术和源码注释,生成需求模型,以指导后续的测试实验和系统改进。 7. **UML建模技术**:UML(Unified Modeling Language...

    基于SSM的青少年心理健康科普系统和微信小程序源码.zip

    标题中的“基于SSM的青少年心理健康科普系统和微信小程序源码”揭示了这是一个使用SSM框架(Spring、SpringMVC、MyBatis)开发的项目,主要目标是为青少年提供心理健康相关的科普信息,并且该系统还包含了一个微信小...

    基础知识.pdf

    在框架篇中,讨论了Spring框架的核心概念和原理,包括BeanFactory和ApplicationContext的区别,SpringBean的生命周期,SpringIOC的实现原理,以及SpringAOP的概念和原理。深入分析了SpringMVC的运行和启动流程,以及...

    基于springboot的恋家房产平台.zip

    在Java中,可能使用了Spring框架的IoC(Inversion of Control)和AOP(Aspect Oriented Programming)特性,来实现对象的管理和切面编程,从而提高代码的模块化和可维护性。 在标签中提到的"毕业设计",表明这是一...

    JAVA医药管理系统设计(论文+源代码).rar

    系统可能使用Spring框架来管理依赖和处理事务,Spring提供了IoC(Inversion of Control)和AOP(Aspect-Oriented Programming)功能,简化了开发过程。此外,Spring MVC作为Spring的一部分,可以用于构建前端控制器...

    圣思园Java.docx

    - **Spring框架**:剖析Spring IoC容器、AOP实现、数据库操作组件及事务处理机制。 #### 源代码分析 - **框架源码剖析**:通过分析框架源码提升开发者对技术的理解和应用能力。 - **Struts2**、**Hibernate**与**...

    动力节点java课程.docx

    6. **Spring框架**:深入理解IoC容器、AOP和声明式事务,学习Spring的自动装配特性。 通过这三个阶段的学习,学员将具备扎实的Java基础,全面的Java Web开发能力,以及在实际项目中应用流行框架解决问题的能力,为...

    J2EE课程总结

    - 是一个开放源码的对象关系映射框架,可以将Java类映射到数据库表及其字段上。 **2. Hibernate的工作原理** - Hibernate通过配置文件或注解来定义对象与数据库表之间的映射关系,并提供一系列API来进行数据的增删...

    详细设计说明书1

    使用Java反射机制实现代理模式,结合Spring框架的Bean、IoC和DI(工厂方法模式),以及Netty的责任链模式和装饰者模式,Mybatis的ORM(动态代理工厂)进行代码设计。 7.2. 自定义设计包括单例模式、拦截器和抽象...

    java运维简历.docx

    4. **开源框架(Struts1、Hibernate3、Spring2.5)**:熟悉Struts1的执行流程,理解Hibernate的对象-关系映射(ORM)和性能优化,了解Spring的IoC容器和AOP切面编程。这些经验显示他能有效利用这些框架来构建复杂的...

    MyEclipse 6 Java EE 开发中文手册.pdf

    - **Spring:** 轻量级 IoC 和 AOP 容器,简化企业级应用开发。 **九、MyEclipse UML 开发:** - **绘制 UML 图:** 使用内置工具绘制 UML 类图、序列图等。 - **代码生成:** 从 UML 图生成代码。 - **逆向工程:...

    成为Java高手的25个学习目标.doc

    14. **轻量级框架**:熟悉Spring、PicoContainer、Avalon等轻量级应用框架,理解IoC(依赖注入)和DI(构造器注入、接口注入)的概念。 15. **J2EE技术**:掌握JNDI(Java命名和目录接口)、JMS(Java消息服务)、...

Global site tag (gtag.js) - Google Analytics