• 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>
  • 相关阅读:
    js获取粘贴内容
    axios导出 exer
    Mac + IDEA + JRebel破解方法.
    富有魅力的git stash
    java web 下实现文件下载
    java23中设计模式
    高并发量网站解决方案
    Linux下拆分大文件
    Linux下jvm、tomcat、mysql、log4j优化配置
    cas单点登出
  • 原文地址:https://www.cnblogs.com/Ch1nYK/p/8452396.html
Copyright © 2020-2023  润新知