菜鸟的spring 3.0源码学习之旅(5)

今天天气大范围降温,或许对于南方还是阳春三月的气候,但是对于我们这里,就将要进入千里冰封万里雪飘的季节了,不仅如此,我柔弱的手机也禁不住这大范围的降温也因此进入了休眠状态

不过阵阵的寒意毅然挡不住我学习的热情,我下定决心,在我变身成为冰雕之前,一定要先把spring的源码搞懂,因为吧spring都搞懂了,春天还远吗

不瞎扯了,言归正传吧

昨天呢,我们讲述了XmlBeanFactory的字段实例化所发生的动作,那么今天呢,我们主要是讨论一下构造器里发生的一切,

首先,我们再看一下这个构造器

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {

              super(parentBeanFactory);

              this.reader.loadBeanDefinitions(resource);  //加载BeanDefinitions信息

}

在这个构造器里,第一句的意思是说,吧parentBeanFactory交给父类的构造器来处理,

public AbstractAutowireCapableBeanFactory() {

              super();

              ignoreDependencyInterface(BeanNameAware.class);

              ignoreDependencyInterface(BeanFactoryAware.class);

              ignoreDependencyInterface(BeanClassLoaderAware.class);

       }

       public AbstractAutowireCapableBeanFactory(BeanFactory parentBeanFactory) {

              this();

              setParentBeanFactory(parentBeanFactory);

       }

在这个构造器里,我们可以看到,构造器里实际上做了两个工作,一个是调用ignoreDependencyInterface,一个是调用了其父类的setParentBeanFactory,第一个工作实际上是往private final Set<Class> ignoredDependencyInterfaces = new HashSet<Class>();这个字段里设置添加参数,第二个呢,是吧这个入参设置到父类的私有字段里

不过呢,当这个类在实例化的同时,这个静态代码会先获得执行

private static Class javaxInjectProviderClass = null;

static {

              ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();

              try {

                     javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");

              }

              catch (ClassNotFoundException ex) {

              }

       }

这个是为该字段动态的添加类实例信息,这个我到目前还没有发现有什么有用的地方,所以咱们暂时先忽略这个地方

XmlBeanFactory构造器里第一行代码就执行完了,那么我们就开始研究第二行代码吧

this.reader.loadBeanDefinitions(resource);

这个呢,是XmlBeanFactory的字段调用了loadBeanDefinition方法,那么,我们就欣赏一下这个方法的实现吧

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {

              return loadBeanDefinitions(new EncodedResource(resource));

       }

这个方法的主要作用是吧Resource封装成EncodedResource类,这个EncodedResource类呢,有两个字段,一个是字符串类型的编码格式字段,另一个是Resource信息,这样大家应该就了解的差不多了吧,所以也不再赘述,我们然后再往下看

org.springframework.beans.factory.xml.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) {  //如果变量为null,则实例化,并添加到本地线程中

                     currentResources = new HashSet<EncodedResource>(4);

                     this.resourcesCurrentlyBeingLoaded.set(currentResources);

              }

              if (!currentResources.add(encodedResource)) {   //如果currentResources包含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();

                     }

              }

       }

这个方法貌似比较复杂,不过我们别着急,看我耐着心给大家分析

Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

              if (currentResources == null) {  //如果变量为null,则实例化,并添加到本地线程中

                     currentResources = new HashSet<EncodedResource>(4);

                     this.resourcesCurrentlyBeingLoaded.set(currentResources);

              }

              if (!currentResources.add(encodedResource)) {   //如果currentResources包含encodedResource,则抛出异常

                     throw new BeanDefinitionStoreException(

                                   "Detected cyclic loading of " + encodedResource + " - check your import definitions!");

              }

这个主要是往字段中添加资源,这个字段是用本地线程包装的,我们来看这个字段

private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =

                     new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded");

然后我让大家看下面的这个语句段

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();

                     }

InputSource是对要解析的XML文件的一个抽象,资源返回输出流,然后由InputSource实例化,如果资源的编码方式不为null,则设置其格式,然后将会执行doLoadBeanDefinitions方法

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)

                     throws BeanDefinitionStoreException {

              try {

                     int validationMode = getValidationModeForResource(resource);  //XSD

                     Document doc = this.documentLoader.loadDocument(

                                   inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); 

                     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);

              }

       }

这个是本类的doLoadBeanDefinitions方法,在这个方法里,主要是吧InputSource还有资源文件解析成Document,我想这个大家应该一目了然,也不需要多说,

int validationMode = getValidationModeForResource(resource);

在此方法中的这个字段是为了获得validationMode的值,在这里,此值默认为xsd,

getEntityResolver()此方法是为了实例化EntityResolver

不过,在这个方法里,真正的重点是这个

Document doc = this.documentLoader.loadDocument(

                                   inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); 

这个字段正是此方法的核心所在,那么我们看看loadDocument方法都进行了什么处理了

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,

                     ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

 

              DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);//实例化此类,并且把验证方式设为dtd验证,支持名称空间

              if (logger.isDebugEnabled()) {

                     logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");

              }

              DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);   //实例化该类,并且指定使用 EntityResolver 解析要解析的 XML 文档中存在的实体,使用指定解析器要使用的 ErrorHandler

              return builder.parse(inputSource);

       }

大家看了这个方法,我想都明白了吧,我也就不多说什么了,接着继续

当执行完doLoadBeanDefinitions以后,紧接着就要执行registerBeanDefinitions方法了

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {

              BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  //实例化BeanDefinitionDocumentReader

              int countBefore = getRegistry().getBeanDefinitionCount();

              documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

              return getRegistry().getBeanDefinitionCount() - countBefore;

       }

在这个方法里,将完成对Document的解析的工作,而这个方法的核心是这个字段

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

那么我们就主要看一下registerBeanDefinition方法吧

org.springframework.beans.factory.xml. DefaultBeanDefinitionDocumentReader#registerBeanDefinitions

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {

              this.readerContext = readerContext;

 

              logger.debug("Loading bean definitions");

              Element root = doc.getDocumentElement();   //获得根元素

 

              BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);   //初始化bean中的信息

 

              preProcessXml(root);   //空方法

              parseBeanDefinitions(root, delegate);

              postProcessXml(root);

       }

那么我们看看createHelper方法都定义了什么吧

protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {

              BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);

              delegate.initDefaults(root);  //初始化bean中的属性

              return delegate;

       }

在这个方法里,它的核心是这个字段

delegate.initDefaults(root);

那么我们再看看initDefaults方法吧

public void initDefaults(Element root) {

              populateDefaults(this.defaults, root);

              this.readerContext.fireDefaultsRegistered(this.defaults);   //尚不清楚作用

       }

下面的这个方法主要对资源中的各个属性取出,设置到DocumentDefaultsDefinition中,      

protected void populateDefaults(DocumentDefaultsDefinition defaults, Element root) {

              defaults.setLazyInit(root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE));

              defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE));

              defaults.setAutowire(root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE));

              defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));

              if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {

                     defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));

              }

              if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {

                     defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));

              }

              if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {

                     defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));

              }

              defaults.setSource(this.readerContext.extractSource(root));    //尚不清楚作用

       }

好了,讲到这里,我就把XmlBeanFactory的实例化过程大体上给梳理了一遍,本人愚笨,用了两天的时间才把其中的缘由搞明白,我想大家都比我聪明,所以还应多请教为是

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值