`
sam406
  • 浏览: 57826 次
  • 性别: 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源码分析(1-10)

    Spring源代码解析(二):ioc容器在Web容器中的启动 Spring源代码分析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务处理...

    spring_ioc

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

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

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

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

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

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

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

    spring5源码分析视频.txt

    spring5源码分析视频,内容包括源码分析、ioc/aop/事务等等,还有手写spring5框架内容

    spring源码分析

    Spring源代码解析(二):ioc容器在Web容器中的启动 3.Spring源代码解析(三):Spring JDBC 4.Spring源代码解析(四):Spring MVC 5.Spring源代码解析(五):Spring AOP获取Proxy 6. Spring源代码解析(六):Spring...

    Spring AOP源码分析.mmap

    有关于Spring,我们最常用的两个功能就是IOC和AOP,前几篇文章从源码级别介绍了Spring容器如何为我们生成bean及bean之间的依赖关系 下面我们接着来看AOP的源码实现。 有关于AOP,我们在面试中也被无数次问到...

    Spring Ioc源码分析系列--自动注入循环依赖的处理.doc

    Spring Ioc源码分析系列--自动注入循环依赖的处理.doc

    Spring Ioc源码分析系列--@Autowired注解的实现原理.doc

    Spring Ioc源码分析系列--@Autowired注解的实现原理.doc

    Spring IoC源码分析1

    1. bean的装配方式 1.表明当前类是一个配置类,是方法bean的源 2.将@Configuration配置的AppConfig的BeanDefinitio

    深入解析Spring IoC:源码与实践指南

    本文深入探讨了Spring IoC容器的加载过程及其源码实现,揭示了Spring中最为根本的概念之一。这包括从AnnotationConfigApplicationContext的实例化开始,到DefaultListableBeanFactory工厂的建立,再到...

    深入解析Spring IoC源码:核心机制与实践应用

    本文深入探讨了Spring框架中IoC容器的源码机制,涵盖了容器的初始化、Bean工厂的实例化、Bean定义的读取及Spring Bean的生命周期管理。通过精细的分析,本文揭示了AnnotationConfigApplicationContext的实例化过程,...

    Spring 源码分析(Bean的初始化)

    Spring 源码分析(Bean的初始化) 前言 本篇文章是个人第一次看spring源码并总结,同时也参考了下面这篇博客。基本也是按照他的思路来理解的。这也算是第一版个人简易理解。也算是窥见spring的冰山一角,之后也会...

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

    NULL 博文链接:https://ziyoujiedao.iteye.com/blog/262360

    Spring源码学习文档,绝对值得好好研究~~

    Spring源代码解析(二):ioc容器在Web容器中的启动.doc Spring源代码分析(三):Spring JDBC.doc Spring源代码解析(四):Spring MVC.doc Spring源代码解析(五):Spring AOP获取Proxy.doc Spring源代码解析(六):...

    Spring高级之注解驱动开发视频教程

    视频详细讲解,需要的小伙伴自行百度网盘下载,链接见附件,永久有效。 1、课程简介 Spring框架是一系列应用框架的核心,也可以说是整合其他应用框架的基座。...n 源码分析-TransactionSynchronizationManager

Global site tag (gtag.js) - Google Analytics