zoukankan      html  css  js  c++  java
  • spring源码分析---2.Bean加载流程

    首先来看下面一段简单的代码

    1 BeanFactory bf = new XmlBeanfactory(new ClassPathResource("spring.xml"));
    2 bf.getBean("testBean");

    这个ClassPathResource类是用于加载classes下的spring配置文件。

    我们来看看这个类的继承关系,Resource接口抽象了所有spring内部使用的底层资源,对不同的资源文件都有对应的实现:文件(FileSystemResource),URL资源(UrlResource),InputStream资源(InputStreamResource)等。

    我们再来看看XmlBeanFactory类的构造方法,this.reader.loadBeanDefinitions(resource)就是资源加载的真正实现,在执行前还调用了下父类的构造方法,我们接下来去看看父类的构造方法。

    1 public XmlBeanFactory(Resource resource) throws BeansException {
    2         this(resource, null);
    3 }
    4 public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
    5         super(parentBeanFactory);
    6         this.reader.loadBeanDefinitions(resource);    //加载资源的真正实现
    7 }

    首先我们来看看XmlBeanFactory的继承关系,

    XmlBeanFactory的父类是DefaultListableBeanFactory,DefaultListableBeanFactory的构造方法如下,那我们再来看看DefaultListableBeanFactory的父类AbstractAutowireCapableBeanFactory。

    1 public DefaultListableBeanFactory() {
    2         super();
    3 }

    AbstractAutowireCapableBeanFactory的构造方法。ignoreDependencyInterface什么作用呢,就是忽略给定接口的自动装配功能。实现了BeanNameAware接口的属性,不会被Spring自动初始化。自动装配时忽略给定的依赖接口,典型应用是通过其他方式解析Application上下文注册依赖,类似于BeanFactory通过BeanFactoryAware进行注入或者ApplicationContext通过ApplicationContextAware进行注入

    1 public AbstractAutowireCapableBeanFactory() {
    2         super();
    3         ignoreDependencyInterface(BeanNameAware.class);
    4         ignoreDependencyInterface(BeanFactoryAware.class);
    5         ignoreDependencyInterface(BeanClassLoaderAware.class);
    6 }

     我们接着来看this.reader.loadBeanDefinitions(resource)方法,doLoadBeanDefinitions(inputSource, encodedResource.getResource())才是核心处理逻辑。

     1 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
     2         Assert.notNull(encodedResource, "EncodedResource must not be null");
     3         if (logger.isInfoEnabled()) {
     4             logger.info("Loading XML bean definitions from " + encodedResource.getResource());
     5         }
     6 
     7         Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
     8         if (currentResources == null) {
     9             currentResources = new HashSet<>(4);
    10             this.resourcesCurrentlyBeingLoaded.set(currentResources);
    11         }
    12         if (!currentResources.add(encodedResource)) {
    13             throw new BeanDefinitionStoreException(
    14                     "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    15         }
    16         try {
    17             InputStream inputStream = encodedResource.getResource().getInputStream();
    18             try {
    19                 InputSource inputSource = new InputSource(inputStream);
    20                 if (encodedResource.getEncoding() != null) {  //当设置了编码属性的时候Spring会使用相应的编码作为输入流的编码
    21                     inputSource.setEncoding(encodedResource.getEncoding());
    22                 }
    23                 return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    24             }
    25             finally {
    26                 inputStream.close();
    27             }
    28         }
    29         catch (IOException ex) {
    30             throw new BeanDefinitionStoreException(
    31                     "IOException parsing XML document from " + encodedResource.getResource(), ex);
    32         }
    33         finally {
    34             currentResources.remove(encodedResource);
    35             if (currentResources.isEmpty()) {
    36                 this.resourcesCurrentlyBeingLoaded.remove();
    37             }
    38         }
    39     }

    我们来看看doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法,

    doLoadDocument(inputSource, resource)这个方法是获取XML文件的验证方式,加载xml文件并得到对应的Document,

    registerBeanDefinitions这个方法是通过返回的Document注册Bean信息

     1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
     2             throws BeanDefinitionStoreException {
     3         try {
     4             Document doc = doLoadDocument(inputSource, resource);
     5             return registerBeanDefinitions(doc, resource);
     6         }
     7         catch (BeanDefinitionStoreException ex) {
     8             throw ex;
     9         }
    10         catch (SAXParseException ex) {
    11             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    12                     "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    13         }
    14         catch (SAXException ex) {
    15             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    16                     "XML document from " + resource + " is invalid", ex);
    17         }
    18         catch (ParserConfigurationException ex) {
    19             throw new BeanDefinitionStoreException(resource.getDescription(),
    20                     "Parser configuration exception parsing XML from " + resource, ex);
    21         }
    22         catch (IOException ex) {
    23             throw new BeanDefinitionStoreException(resource.getDescription(),
    24                     "IOException parsing XML document from " + resource, ex);
    25         }
    26         catch (Throwable ex) {
    27             throw new BeanDefinitionStoreException(resource.getDescription(),
    28                     "Unexpected exception parsing XML document from " + resource, ex);
    29         }
    30     }

    我们主要来看注册bean信息方法吧

    1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    2         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    3         int countBefore = getRegistry().getBeanDefinitionCount();
    4         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    5         return getRegistry().getBeanDefinitionCount() - countBefore;
    6     }
    1 @Override
    2     public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    3         this.readerContext = readerContext;
    4         logger.debug("Loading bean definitions");
    5         Element root = doc.getDocumentElement();
    6         doRegisterBeanDefinitions(root);
    7     }
     1 protected void doRegisterBeanDefinitions(Element root) {
     2         // Any nested <beans> elements will cause recursion in this method. In
     3         // order to propagate and preserve <beans> default-* attributes correctly,
     4         // keep track of the current (parent) delegate, which may be null. Create
     5         // the new (child) delegate with a reference to the parent for fallback purposes,
     6         // then ultimately reset this.delegate back to its original (parent) reference.
     7         // this behavior emulates a stack of delegates without actually necessitating one.
     8         BeanDefinitionParserDelegate parent = this.delegate;  //专门处理解析
     9         this.delegate = createDelegate(getReaderContext(), root, parent);
    10 
    11         if (this.delegate.isDefaultNamespace(root)) {
    12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);  //处理profile属性
    13             if (StringUtils.hasText(profileSpec)) {
    14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
    15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    17                     if (logger.isInfoEnabled()) {
    18                         logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
    19                                 "] not matching: " + getReaderContext().getResource());
    20                     }
    21                     return;
    22                 }
    23             }
    24         }
    25 
    26         preProcessXml(root);
    27         parseBeanDefinitions(root, this.delegate);
    28         postProcessXml(root);
    29 
    30         this.delegate = parent;
    31     }

    解析并注册BeanDefinition

     1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
     2         if (delegate.isDefaultNamespace(root)) {
     3             NodeList nl = root.getChildNodes();
     4             for (int i = 0; i < nl.getLength(); i++) {
     5                 Node node = nl.item(i);
     6                 if (node instanceof Element) {
     7                     Element ele = (Element) node;
     8                     if (delegate.isDefaultNamespace(ele)) {
     9                         parseDefaultElement(ele, delegate);//默认
    10                     }
    11                     else {
    12                         delegate.parseCustomElement(ele);//自定义
    13                     }
    14                 }
    15             }
    16         }
    17         else {
    18             delegate.parseCustomElement(root);//自定义
    19         }
    20     }

     在Spring的XML配置里面有两大类Bean声明,一个是默认的,如:

    1 <bean id="test" class="test.TestBean"/>

    另一类就是自定义的,如:

    1 <tx:annotation-driven>
  • 相关阅读:
    PAT B1045 快速排序 (25 分)
    PAT B1042 字符统计 (20 分)
    PAT B1040 有几个PAT (25 分)
    PAT B1035 插入与归并 (25 分)
    PAT B1034 有理数四则运算 (20 分)
    PAT B1033 旧键盘打字 (20 分)
    HDU 1231 最大连续子序列
    HDU 1166 敌兵布阵
    HDU 1715 大菲波数
    HDU 1016 Prime Ring Problem
  • 原文地址:https://www.cnblogs.com/Ch1nYK/p/8452396.html
Copyright © 2011-2022 走看看