`
sam406
  • 浏览: 59472 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Spring源码分析之IOC2

    博客分类:
  • java
阅读更多
本篇将介绍下ApplicationContext上下文方式的得到bean的源码
上篇用到一个列子
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");


就从ClassPathXmlApplicationContext入手吧
找到它的构造函数
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

调用的是上面的这个
里面又调用另一个构造函数

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}


看到setConfigLocations(configLocations);这个方法,在跟进去咯

public void setConfigLocations(String[] locations) {
		if (locations != null) {
			Assert.noNullElements(locations, "Config locations must not be null");
			this.configLocations = new String[locations.length];
			for (int i = 0; i < locations.length; i++) {
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}
	}



这里面的关键点是
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}


这里面有个属性configLocations其定义如下
private String[] configLocations;
,就是个数组来存放路径的,
在上面关键代码第一行初始化,然后for语句段就是解析路径的。resolvePath方法就不跟进咯,OK,在回到上上面的构造函数里,解释了setConfigLocations方法,在往下走咯。就来到
if (refresh) {
			refresh();
		}
	}


由于传进来的refresh参数是true,所以refresh()方法就会执行咯。好吧,上refresh这牛X的方法
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;
			}
		}
	}


这方法的东西好丰富哦,就各点来击破咯
first 这 synchronized (this.startupShutdownMonitor) 都懂得啥下面first的方法是prepareRefresh();这方法可以忽略咯,就是setting its startup date,
second 就是ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
这里调用的是父类AbstractRefreshableApplicationContext的方法obtainFreshBeanFactory();
源码如下
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

这里面又有别的方法调用咯,第一个方法实现

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);
		}
	}


这里面又调用了createBeanFactory(),看方法就明白意思了啥,就是创建BeanFactory.
protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

在回到refreshBeanFactory()方法中,接下来就是调用loadBeanDefinitions(beanFactory),看意思就是加载beanDefinition了,这个方法是在AbstractRefreshableConfigApplicationContext的子类AbstractXmlApplicationContext实现的

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.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);
	}


这里面创建了一个XmlBeanDefinitionReader 对象,这玩意就是来读取基于XML bean定义的
。而beanDefinitionReader.setResourceLoader(this);这句咯是为reader配置resourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用。initBeanDefinitionReader(beanDefinitionReader);是初始化,而loadBeanDefinitions(beanDefinitionReader);类容多了
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

这里面的有两种方式加载bean咯,一个是Resouce,一个是String,来看下reader.loadBeanDefinitions(configResources);的实现
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int counter = 0;
		for (Resource resource : resources) {
			counter += loadBeanDefinitions(resource);
		}
		return counter;
	}

这里面又调用了 loadBeanDefinitions()这方式的实现是在XmlBeanDefinitionReader中,


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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		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();
			}
		}
		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);
			}
		}
	}

这代码的主要意思是,的到xml文件,并得到IO的InputSource.在返回时有句doLoadBeanDefinitions(inputSource, encodedResource.getResource());这发放的源码

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			int validationMode = getValidationModeForResource(resource);
			Document doc = this.documentLoader.loadDocument(
					inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
			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);
		}
	}

这方法就是加载bean定义在制定的XML文件。主要代码是
Document doc = this.documentLoader.loadDocument(
					inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());


documentLoader的实例 private DocumentLoader documentLoader = new DefaultDocumentLoader();它主要是取得XML文件Document对象。这里就不在详述了,时间有限咯。 
  在取得Document对象后,就要开始注册咯registerBeanDefinitions(doc, resource);就由这方法搞定咯

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// Read document based on new BeanDefinitionDocumentReader SPI.
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}




分享到:
评论

相关推荐

    Spring源码分析_Spring_IOC

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

    Spring源码分析.pdf

    Spring 源码分析 Spring 框架是 Java 语言中最流行的开源框架之一,它提供了一个强大且灵活的基础设施来构建企业级应用程序。在 Spring 框架中,IOC 容器扮演着核心角色,本文将深入分析 Spring 源码,了解 IOC ...

    spring源码分析(1-10)

    2. **IoC 容器**:IoC(Inversion of Control)容器是Spring的核心,负责管理和装配应用中的对象。BeanFactory是基础接口,提供了创建、查找和管理bean的能力。AbstractBeanFactory和DefaultListableBeanFactory是...

    spring_ioc

    这是spring_ioc部分的内容。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。...

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

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

    Spring4 IOC 示例源码

    Spring4 IOC(Inversion of Control,控制反转)是Spring框架的核心特性之一,它极大地简化了Java应用程序的开发。在这个示例源码中,我们可以深入理解并学习如何在实际项目中运用Spring的IOC容器来管理对象的生命...

    Spring5 源码分析(第 2 版)-某Tom老师

    《Spring5 源码分析(第 2 版)》是某Tom老师精心编写的深度解析文档,旨在帮助读者全面理解Spring5的核心机制和设计理念。Spring作为Java领域最为广泛应用的框架之一,其源码的深入理解对于开发者来说至关重要。这篇...

    spring-IOC-AOP调用大致过程(源码分析)

    spring version: 5.0.0; jdk: 1.8 IOC大致调用顺序(IOC调用的AOP标签解析)

    【框架源码篇 01】Spring源码-手写IOC

    通过分析和手写Spring的IOC源码,我们可以更好地理解Spring的工作原理,从而更有效地利用它来构建我们的应用程序。在01-手写IoC源码-spring-v1.zip文件中,你将找到逐步实现这个过程的代码示例,这将帮助你加深对...

    Spring IoC源码深度剖析开源架构源码2021.pdf

    5. **搭建Spring源码阅读环境** - 从GitHub下载Spring框架的源码。 - 安装和配置 `gradle`、Idea等开发工具。 - 根据Spring的模块结构编译源码,通常需要按照 `core-oxm-context-beans-aspects-aop` 的顺序进行。...

    Spring ioc源码解读

    通过对Spring IoC容器的理解和源码分析,我们可以深入了解到Spring框架是如何管理和控制应用对象的生命周期及依赖关系的。在实际开发中,了解Spring IoC容器的工作原理有助于更好地利用Spring框架,提高开发效率和...

    Spring源码分析

    以上只是Spring源码分析的部分内容,实际源码中还包括Spring的其他模块,如Spring Batch(批处理)、Spring Security(安全)、Spring Integration(集成)等。理解并掌握Spring源码,有助于我们更好地利用Spring...

    spring源码分析(一)

    ### Spring源码分析知识点 #### 一、Spring框架概述 Spring框架是一个全面的企业级应用开发框架,它通过一系列模块化的组件来支持不同的应用场景和技术需求。Spring的核心价值在于提供了一种简洁的方式来解决企业...

    Spring源码解析.zip

    本压缩包“Spring源码解析”提供了对Spring框架核心组件——IOC(Inversion of Control,控制反转)、AOP(Aspect Oriented Programming,面向切面编程)以及Transaction(事务管理)的源码分析,帮助开发者更全面地...

    老王读spring-ioc源码分析&amp;测试代码.zip

    老王读 Spring IoC 系列文章的源码分析&测试代码 Spring IoC 源码分析,帮助大家学习 Spring 源码,更加了解 Spring 的底层 博客专栏地址:https://blog.csdn.net/wang489687009/category_11269905.html

    spring 源码中文注释

    在源码分析的过程中,读者会深入理解Spring的内部工作机制,例如如何解析配置、如何创建bean实例、如何实现AOP代理等。这将有助于开发者编写更高效、更健壮的代码,也能为参与Spring的扩展或定制打下坚实基础。 总...

    Spring IoC源码分析1

    Spring 框架的核心特性之一是Inversion of Control(IoC),也被称为依赖注入(Dependency Injection,DI)。IoC使得应用程序中的对象不再负责创建和管理它们的依赖对象,而是将这个责任交给了一个外部的容器,即...

    Spring 5.2.9的IOC核心jar包

    **源码分析** 对于学习和理解Spring框架,查看源码是很有帮助的。你可以深入研究这些jar包中的类和方法,了解Spring如何管理Bean,如何解析配置,以及如何执行依赖注入等操作。 总的来说,Spring 5.2.9的IOC核心jar...

    spring源码分析

    《Spring源码分析》 Spring框架作为Java领域中不可或缺的一部分,其强大之处在于它提供了丰富的功能,包括依赖注入(Dependency Injection,简称DI)、面向切面编程(Aspect-Oriented Programming,简称AOP)、事务...

Global site tag (gtag.js) - Google Analytics