springIOC源码解析(五)
2016-11-11 16:03
357 查看
现在咱们来看一下ApplicationContext是怎么初始化容器的
进入ClassPathXmlApplicationContext的构造函数会发现最终进入了如下的重载构造函数,其中refresh()方法就是容器初始化的入口
refresh()方法如下
这里定义了IOC容器初始化的过程,使用了模板模式,首先咱们看第二行创建BeanFactory的过程
refreshBeanFactory()方法在AbstractRefreshableApplicationContext中实现,咱们接着进去看看
分析一下这里的逻辑:首先判断一下BeanFactory是否存在,如果存在则把已有的BeanFactory销毁掉(因为传入的refresh为true,即要重新加载);然后会创建一个用DefaultListableBeanFactory实现的BeanFactory;再然后通过loadBeanDefinitions()方法载入bean信息
这里是不是就和BeanFactory初始化容器很像了:在初始化BeanFactory之后载入bean
咱们接着看看如何载入bean,这里中间经过好几个跳转,最终实现如下
loadBeanDefinitions()方法会跳到如下方法中
咱们再看try块中的doLoadBeanDefinitions()方法
这里的逻辑很好理解,把Resource转成Document接口,这是解析XML的方式之一,解析XML之后进行bean注册
registerBeanDefinitions()方法经过跳转之后会进入如下方法
这些代码很眼熟有没有?没错,这就是BeanFactory加载bean的方法.所以接下来如何管理bean我就不继续往下看了,想了解的同学可以看看我前面的博客
OK,咱们回到容器初始化模板的地方,再说一个比较重要的方法finishBeanFactoryInitialization(),这个方法作用是什么呢?预知后事如何,且看下回分解
ApplicationContext ctx = new ClassPathXmlApplicationContext("springioc.xml"); Engine engine2 = (Engine)ctx.getBean("engine"); System.out.println(engine2.getBrandName()); Car car2 = (Car)ctx.getBean("car"); car2.introduce();
进入ClassPathXmlApplicationContext的构造函数会发现最终进入了如下的重载构造函数,其中refresh()方法就是容器初始化的入口
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
refresh()方法如下
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) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
这里定义了IOC容器初始化的过程,使用了模板模式,首先咱们看第二行创建BeanFactory的过程
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
refreshBeanFactory()方法在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); } }
分析一下这里的逻辑:首先判断一下BeanFactory是否存在,如果存在则把已有的BeanFactory销毁掉(因为传入的refresh为true,即要重新加载);然后会创建一个用DefaultListableBeanFactory实现的BeanFactory;再然后通过loadBeanDefinitions()方法载入bean信息
这里是不是就和BeanFactory初始化容器很像了:在初始化BeanFactory之后载入bean
咱们接着看看如何载入bean,这里中间经过好几个跳转,最终实现如下
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; } }
loadBeanDefinitions()方法会跳到如下方法中
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.remove(); } } }
咱们再看try块中的doLoadBeanDefinitions()方法
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); } }
这里的逻辑很好理解,把Resource转成Document接口,这是解析XML的方式之一,解析XML之后进行bean注册
registerBeanDefinitions()方法经过跳转之后会进入如下方法
protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. 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; }
这些代码很眼熟有没有?没错,这就是BeanFactory加载bean的方法.所以接下来如何管理bean我就不继续往下看了,想了解的同学可以看看我前面的博客
OK,咱们回到容器初始化模板的地方,再说一个比较重要的方法finishBeanFactoryInitialization(),这个方法作用是什么呢?预知后事如何,且看下回分解
相关文章推荐
- Spring源码解析-IOC容器的实现
- 【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)
- 【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【I】
- spring培训第一讲-ioc实现原理源码解析
- spring ioc 源码解析
- Spring源码解析-IOC容器的实现-ApplicationContext
- 做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析之一
- spring源码解析-Ioc1
- spring ioc 源码解析(二)
- Spring源码分析--Ioc容器定位解析资源文件并注册BeanDefinition
- 【Spring源码解析】之IOC容器在Web容器中的启动
- 【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)
- 做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析后记1
- [Spring3.x源码]IoC(二)解析XML建立上下文
- (六)Spring核心框架 - IOC的源码解析
- spring IoC源码分析 (3)Resource解析
- 【Spring源码解析】之IOC容器
- Spring源码解读-Spring IoC容器初始化之资源解析
- 做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析后记2