Spring核心-XmlBeanFactory

Spring框架在开发中还是在面试中都占有很重要的地位,AOP,IOC两个概念也是Spring的核心。之前一直想学习一下IOC的实现原理,刚好趁着周六周天就学习了一下IOC的一个基础实现XmlBeanFactory,了解的从解析xml到注册到IOC容器的过程收货满满。写了这边博客与大家分享一下,刚好也是交流一下技术,如果文章中有不对的地方,大家可以交流探讨。

XmlBeanFactory继承关系图

在这里插入图片描述

代码分析

  • XmlBeanFactory
// DefaultListableBeanFactory 是一个基础IOC容器
public class XmlBeanFactory extends DefaultListableBeanFactory {
    // 从xml文件中对definition进行加载解析从bean并进行注册(由于容器本身没资源加载
    // 和解析的功能所以通过XmlBeanDefinitionReader 对象来实现)
    private final XmlBeanDefinitionReader reader;
   // 构造器(资源信息)
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, (BeanFactory)null);
    }
    // 构造器(资源信息,父bean工厂)
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        // 初始化父类
        super(parentBeanFactory);
        // 创建读取,解析,注册xml中bean(当前对象引用)的对象
        this.reader = new XmlBeanDefinitionReader(this);
        // 调用loadBeanDefinitions方法初始化ioc容器对
        // xml中的definition进行加载,解析,注册到ioc容器中
        this.reader.loadBeanDefinitions(resource);
    }
}

从代码中可以发现对这些XML文件定义信息的处理并不是由XmlBeanFactory直接完成的。在XmlBeanFactory中初始化了一个XmlBeanDefinitionReader对象,有了这个Reader对象,那些以XML方式定义的BeanDefinition就有了处理的地方。
构造XmlBeanFactory这个IOC容器时,需要指定BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类类给出。Resource是Spring用来封装I/O操作的类。 比如,我们的BeanDefinition信息以XML文件形式存在的,那么可以使用像“ClassPathResource res= new ClassPathResource (bean.xml) ”;这样具体的ClassPathResource 来构造需要的Resource,然后将Resource作为构造参数传递给XmlBeanFactory构造函数。这样,Ioc容器就可以方便的定位到需要的BeanDefinition信息来对Bean完成容器的初始化和依赖注入。

  • XmlBeanDefinitionReader

1.loadBeanDefinitions方法

// 加载 Bean (资源路径信息)
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        // EncodedResource(资源编码)包含的资源路径信息
        return this.loadBeanDefinitions(new EncodedResource(resource));
    }

2.loadBeanDefinitions方法

  public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
       // 判断EncodedResource 是否为null
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (this.logger.isTraceEnabled()) {
        // 打印 加载xml中bean的资源路径信息
            this.logger.trace("Loading XML bean definitions from " + encodedResource);
        }
        // 获取当前线程中正在加载的资源
        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        // 判断当前将要加载是否已经存在
        if (!currentResources.add(encodedResource)) {
        // 抛出检测到“+encodedResource+”的循环加载 - 检查您的导入定义
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
        // 定义int类型的 var6
            int var6;
            try {
            // 获取加载资源输入流
                InputStream inputStream = encodedResource.getResource().getInputStream();
                // 定义Throwable类型的var4
                Throwable var4 = null;

                try {
                // 创建资源输入对象
                    InputSource inputSource = new InputSource(inputStream);
                    // 判断资源编码是否为null
                    if (encodedResource.getEncoding() != null) {
                    // 设置资源输入时的编码
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    // 调用doLoadBeanDefinitions(资源输入对象,资源信息)
                    var6 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } catch (Throwable var24) {
                    var4 = var24;
                    throw var24;
                } finally {
                    if (inputStream != null) {
                        if (var4 != null) {
                            try {
                                inputStream.close();
                            } catch (Throwable var23) {
                                var4.addSuppressed(var23);
                            }
                        } else {
                            inputStream.close();
                        }
                    }

                }
            } catch (IOException var26) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var26);
            } finally {
                currentResources.remove(encodedResource);
                if (currentResources.isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var6;
        }
    }

3.doLoadBeanDefinitions方法

// 资源输入对象,资源信息
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
             // 得到一个xml的Document 对象
            Document doc = this.doLoadDocument(inputSource, resource);
            // 注册 Bean(xml的Document 对象,资源信息)
            int count = this.registerBeanDefinitions(doc, resource);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Loaded " + count + " bean definitions from " + resource);
            }

            return count;
        } catch (BeanDefinitionStoreException var5) {
            throw var5;
        } catch (SAXParseException var6) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var6.getLineNumber() + " in XML document from " + resource + " is invalid", var6);
        } catch (SAXException var7) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var7);
        } catch (ParserConfigurationException var8) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var8);
        } catch (IOException var9) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var9);
        } catch (Throwable var10) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var10);
        }
    }

4.doLoadDocument方法

// 资源输入对象,资源信息
 protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
 // 资源输入对象,实体解析器,错误处理程序,资源验证,命名空间感知
        return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware());
    }

5.registerBeanDefinitions方法

 // 注册 Bean(xml的Document 对象,资源信息)
 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
         // 创建从Document中读取bean的阅读器
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
 
        // DefaultListableBeanFactory 容器实现了BeanDefinitionRegistry接口
        // 说明BeanDefinitionRegistry容器本身也具备了bean注册的功能
        // 这里获取的是DefaultListableBeanFactory 容器中存放bean的Map的大小
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        // 开始想IOC容器中进行bean的注册
        // 底层实现是使用DefaultListableBeanFactory容器本身进行bean的注册
        // DefaultListableanBeanFactory中有个方法
        //public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 
        // 是进行bean注册的具体可以去看源码
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        // 获取Map大小
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

6.createBeanDefinitionDocumentReader方法

    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
        return (BeanDefinitionDocumentReader)BeanUtils.instantiateClass(this.documentReaderClass);
    }

  • DocumentLoader(DocumentLoader是一个接口默认的实现只有一个DefaultDocumentLoader)
    1.loadDocument方法
 public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
       // 得到DocumentBuilderFactory工厂
        DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isTraceEnabled()) {
            logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        // 创建文档生成器(工厂,实体解析器,错误处理程序)
        DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
        // DocumentBuilder 的parse方法得到一个Xml的Documnet对象
        return builder.parse(inputSource);
    }

2.createDocumentBuilderFactory方法

// 资源验证,命名空间感知
 protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException {
       // 创建文档生成器工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 设置工厂命名感知器
        factory.setNamespaceAware(namespaceAware);
        // 资源认证不为0
        if (validationMode != 0) {
        // 认证成功
            factory.setValidating(true);
            // 认证结果为3
            if (validationMode == 3) {
            // 设置工厂命名感知器为true
                factory.setNamespaceAware(true);
             // 工厂设置属性
                try {
                    factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
                } catch (IllegalArgumentException var6) {
                    ParserConfigurationException pcex = new ParserConfigurationException("Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
                    pcex.initCause(var6);
                    throw pcex;
                }
            }
        }
// 返回工厂
        return factory;
    }

3.createDocumentBuilder方法

    protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory, @Nullable EntityResolver entityResolver, @Nullable ErrorHandler errorHandler) throws ParserConfigurationException {
    // 由工厂得到一个DocumentBuilder 
        DocumentBuilder docBuilder = factory.newDocumentBuilder();
        // 判断实体解析器不为null
        if (entityResolver != null) {
        // 设置DocumentBuilder 的实体解析器
            docBuilder.setEntityResolver(entityResolver);
        }
        // 错误处理器不为null
        if (errorHandler != null) {
        // DocumentBuilder 的错误处理器
            docBuilder.setErrorHandler(errorHandler);
        }
        // 返回DocumentBuilder 
        return docBuilder;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值