SPRING源码学习之路(一)
来源:互联网 发布:alexnet网络 编辑:程序博客网 时间:2024/05/17 00:55
结合《Spring技术内幕:深入解析SPRING架构与设计原理》这本书开启Spring学习之路。
ps:之前其实已经看过一部分了,但是也就是看过,一看而过了。o(╯□╰)o
结合FileSystemXmlApplicationContext来分析 具体实现如下:
//对象初始化时候 调用refresh(),启动了BeanDifinition载入过程public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();}}
refresh()方法的实现:
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// 调用子类 refreshBeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 准备beanFactoryprepareBeanFactory(beanFactory);try {//设置beanFactory的后置处理.postProcessBeanFactory(beanFactory);// 调用beanFactory的后置处理器,这些后处理器是在Bean定义中向容器注册的invokeBeanFactoryPostProcessors(beanFactory);// 注册bean的后处理器,在bean创建过程中调用registerBeanPostProcessors(beanFactory);// 初始化上下文中的消息源initMessageSource();// 初始化事件机制initApplicationEventMulticaster();// 初始化其他特殊beanonRefresh();// 检测监听bean,并向容器注册registerListeners();// 实例化所有 (non-lazy-init) 单例finishBeanFactoryInitialization(beanFactory);// 发布容器事件,结束Refresh过程finishRefresh();}catch (BeansException ex) {logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);// 防止bean资源占用,在异常处理中,销毁已经在前面生成的bean单件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容器的启动,蕴含了BeanDefinition的Resource定位,载入,注册等三个过程
在refresh()方法中可以看到调用了子类 refreshBeanFactory()方法,在其子类AbstractRefreshableApplicationContext中的实现
@Overrideprotected final void refreshBeanFactory() throws BeansException {if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try { //创建beanFactory 类型为DefaultListableBeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);loadBeanDefinitions(beanFactory);// 启动对BeanDefinition的载入synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}
loadBeanDefinitions的具体实现在AbstractRefreshableApplicationContext子类 AbstractXmlApplicationContext中,代码:
@Overrideprotected 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,// 启动bean定义信息的载入过程.initBeanDefinitionReader(beanDefinitionReader);loadBeanDefinitions(beanDefinitionReader);}可以看到 这里创建了XmlBeanDefinitionReader 设置到beanFactory 为reader配置resourceLoader
接着就是loadBeanDefinitions调用地方
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);}}调用了reader也就是 XmlBeanDefinitionReader 的 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();}}}具体读取过程 在doLoadBeanDefinitions中实现
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try { // 获取XML文件document,解析过程由documentLoader完成Document doc = doLoadDocument(inputSource, resource); // 这里启动对BeanDefinition解析的详细过程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);}}
我们重点关注 registerBeanDefinitions方法的具体实现
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;}这里调用上面提到 documentReader 对应的registerBeanDefinitions方法
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;logger.debug("Loading bean definitions");Element root = doc.getDocumentElement();doRegisterBeanDefinitions(root);}具体过程在doRegisterBeanDefinitions中实现
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;}可以看到其中创建了bean定义信息的解析代理类 具体解析过程在 parseBeanDefinitions中实现
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);}}默认解析元素方法 parseDefaultElement
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)) {// recursedoRegisterBeanDefinitions(ele);}}
可以看到通过if else 对元素类型进行区分 ,我们重点关注 bean标签的解析过程
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// 向IOC容器注册解析得到的beanDefinitionsBeanDefinitionReaderUtils.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));}}
这就是大体的载入过程
大体流程图:
0 0
- SPRING源码学习之路(一)
- spring源码解析(一)迈向学习spring之路
- spring源码学习之路---环境搭建(一)
- spring源码学习之路---环境搭建(一)
- spring源码学习之路---环境搭建(一)
- spring源码学习之路---环境搭建(一)
- spring源码学习之路---IOC初探(一)
- spring源码学习(一)
- Spring源码学习(一)
- Spring源码学习(一源码下载)
- SPRING源码学习之路(二)
- spring 源码学习笔记(一)—— spring ioc 之加载XML转换为BeanDefinition
- Spring源码学习(一)------ IoC
- Spring源码学习(一)------ IoC
- Spring源码学习(一)------ IoC
- spring 源码学习 初始化(一)
- Spring IOC核心源码学习(一)
- Spring源码学习(一)------ IoC
- winscp 向Ubuntu传输文件提示错误码3:permmision denied解决方法
- js 打开视频文件,测试已通过
- MySQL 5.7主从同步延迟优化大全
- iOS中的缓存计算和清除(二)
- C++期末大作业-简易通讯录
- SPRING源码学习之路(一)
- Android webview实现h5视频全屏播放兼容Android7.0,自己添加webview库兼容全部版本
- AutoMapper使用
- JavaScript深拷贝与浅拷贝的区别
- 设计模式之装饰者模式
- CentOS下g++: command not found问题的解决
- 色值的透明度与十六进制代码转换
- centos安装web流量查看于监测工具vnstat-php-frontend
- MJExtension 字典转模型