springIOC源码解析(五)
来源:互联网 发布:php在线客服 编辑:程序博客网 时间:2024/05/16 12:28
现在咱们来看一下ApplicationContext是怎么初始化容器的
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(),这个方法作用是什么呢?预知后事如何,且看下回分解
- springIOC源码解析(五)
- SpringIOC--初始化源码解析
- SpringIOC--初始化源码解析
- SpringIOC--初始化源码解析
- springIOC源码解析(一)
- springIOC源码解析(二)
- springIOC源码解析(三)
- springIOC源码解析(四)
- springIOC源码解析(六)
- SpringIOC源码解析
- SpringIOC源码解析
- SpringIOC源码序列图
- SpringIOC个人解析
- TFS源码解析五
- Vue源码解析(五)
- springIoC
- springIoc
- SpringIOC
- 通讯之——在ARM Linux上的实现(2440)
- VS2010 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- serialVersionUID的思考
- [BZOJ1657][Usaco2006 Mar]Mooo 奶牛的歌声(单调栈)
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- springIOC源码解析(五)
- Opencv学习笔记(1)_MAT图像与HBITMAP互相转换
- 手把手教你用Spring Cloud和Docker构建微服务
- 乐行天下激光雷达数据口测试
- springMVC基于hibernate validator的表单验证示例
- COLD VS HOT OBSERVABLES
- 基于MFC对话框工程如何使用另一工程下的对话框
- 用抓包工具Fidder查看请求数据
- mark-----安卓类项目产线生产测试流程总结