spring源码之IOC的核心部分
Posted lucas2
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring源码之IOC的核心部分相关的知识,希望对你有一定的参考价值。
前言
上一篇对启动时的整个流程进行了大体的分析,这一篇ioc的核心部分进行分析。包括初始化过程和依赖注入过程。
概述
在分析之前先看几个类图
DefaultListableBeanFactory是ioc的一个核心类,可以看到我们关心的bean定义和单例bean都注册在它的属性上。
ClassPathXmlApplicationContext注意一下,它实现了事件发布、资源解析、消息源、资源加载的几个接口。
ClassPathXmlApplicationContext实现了资源加载接口,可以把xml配置的信息加载到Resource对象中。
XmlBeanDefinitionReader把Resouce中的内容读到Document对象中
DefaultBeanDefinitionDocumentReader负责把读取Document内容转化成BeanDefinition对象
源码分析之初始化过程
- 接着上篇的源码进行分析,直接来到在AbstractApplicationContext类的refresh方法中调用的obtainFreshBeanFactory方法。这个方法是我们初始化过程的入口。这个方法做了三件事
- 创建一个DefaultListableBeanFactory
- 把配置文件中的bean定义转换成BeanDefintion对象并注册到DefaultListableBeanFactory上
- 返回这个DefaultListabelBeanFactory对象
//AbstractApplicationContext类的方法
//创建并返回DefaultListableBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
- 刷新beanFactory,这个方法主要分为四步,我们关心的是第二步和第四步
- 如果之前已经有创建过beanFactory,那么这里会对注册在它上面的bean进行销毁,并关闭这个beanFactory
- 创建一个beanFactory,这个就是去创建一个DefaultListBeanFactory
- 一些对beanFactory的自定义处理,这里设置了bean定义是否可以重写,是否可以循环引用
- 最后,也是最重要的,加载bean定义
//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) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
- 加载bean定义,这里主要做了三件事。在这里我们看到了创建了一个XmlBeanDefinitionReader对象
- 创建XmlBeanDefinitionReader对象
- 进行一些设置和加载前的处理
- 加载bean定义,继续向下委派
//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.setEnvironment(this.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); }
- 拿到Resource对象,整个过程如下
- 如果是Resource对象,则直接加载。但由于我们这里是路径,先对每一个路径进行循环
- 拿到ResourceLoader,当前ClassPathXmlApplicationContext对象就是并且它实现了ResourcePatternResolver接口,那么用当前的上下文对象把定义路径上的xml文件读取到Resource对象中
- XmlBeanDefinitionReader掊下来再对Resource对象进行加载
//AbstractXmlApplicationContext类的方法
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); } }
//AbstractBeanDefinitionReader类的方法 public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; for (String location : locations) { counter += loadBeanDefinitions(location); } return counter; }
//AbstractBeanDefinitonReader类的方法 public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null); }
//AbstractBeanDefinitionReader类的方法 public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
- 把Resource对象封装成InputSource对象
//AbstractBeanDefinitionReader类的方法
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; }
//XmlBeanDefinitionReader类的方法 public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); }
//XmlBeanDefintionReader类的方法 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()); } //使用ThreadLocal,实现随用随取 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.remove(); } } }
- 通过DefaultDocumentLoader把InputSource对象读取到Document对象中
//XmlBeanDefinitionReader类的方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); 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); } }
- 创建BeanDefintionDocumentReader对象,这里创建的是DefaultBeanDefiniitonDocumentReader对象
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
- 获取合适的解析器。创建一个BeanDefintionParserDelegate对象,这个对象可以帮助找到合适解析器,在AOP的分析中有说到,这里不说明。对于bean命名空间下的,会走默认的元素解析。 这里我们可以先看到对profile标签进行了解析
//DefaultBeanDefintionDocumentReader类的方法
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } //DefaultBeanDefintionDocumentReader类的方法 protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
//DefaultBeanDefintioinDocumentReader类的方法 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); } }
- 这里我们看到了对我们常用的import,alias,bean,beans进行了解析。现在我们着重看下对bean的解析
//DefaultBeanDefintionDocumentReader类的方法 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
- bean标签的解析,这里很显然的两步
- 解析element得到BeanDefinitionHolder
- 注册BeanDefintion
//DefaultBeanDefintionDocumentReader类的方法 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name ‘" + bdHolder.getBeanName() + "‘", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
总结
本篇主要对spring启动时的做了描述,比较说事件、后置处理器注册等等。下一篇会对spring的核心-ioc进行总结
参考链接
https://www.cnblogs.com/niejunlei/archive/2016/11/11/6054713.html(prepareBeanFactory)
https://www.cnblogs.com/wade-luffy/p/6074088.html(生命周期后置处理器)
https://blog.csdn.net/zhangduilei/article/details/76172355(注册JMX)
以上是关于spring源码之IOC的核心部分的主要内容,如果未能解决你的问题,请参考以下文章
Spring5源码分析(006)——IoC篇之核心类DefaultListableBeanFactory和XmlBeanDefinitionReader