zoukankan      html  css  js  c++  java
  • 初始化IoC容器(Spring源码阅读)-我们到底能走多远系列(31)

    我们到底能走多远系列(31)

    扯淡:

      有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的。未婚的你们,你们是怎么分配工资的?

      毕竟,对自己的收入的分配差不多体现了自己的现状,以及自己对自己未来有什么样的期许~

      

    主题:

      本人在阅读源码基本参考了《Spring技术内幕:深入解析 Spring架构与设计原理》,很不错的书籍,建议大家阅读。

      初始化IoC容器:1,resource定位  2,BeanDefinition载入  3,把BeanDefinition载入到IoC

    重要的解释:

      Spring中的IoC容器,所谓的容器核心就是个hashMap,准确的说是ConcurrentHashMap,键值对就是:<String, BeanDefinition> key是bean的name。

      那么BeanDefinition就是对外界bean描述的抽象,比如你写的<bean>标签,最会被抽象成一个BeanDefinition放进这个Map中去。

      所以一个完整的IoC容器来说,只要提供对这个Map的必要操作就可以了。一般DefaultListableBeanFactory 作为一个默认功能完整的IoC容器来使用。

      上面的解释已经很清楚了,IoC容器的初始化就可以理解成,我们有个xml描述了一些bean的属性,Spring把它读进来,按照自己的规则解析一边,把其中的Bean描述转换成一个个BeanDefinition放进Map中去就完成初始化了。

      FileSystemXmlApplicationContext为例子看一下源码中是如何实现的:(希望有兴趣的先看下Spring中BeanFactory下面的继承结构)

      我们会写类似下面的代码开始我们的Spring之旅:

    ApplicationContext ct = new FileSystemXmlApplicationContext("src/service/service.xml");


    FileSystemXmlApplicationContext
    的构造函数:

    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
            this(new String[] {configLocation}, true, null);
        }
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                throws BeansException {
    
            super(parent);
            setConfigLocations(configLocations);
            if (refresh) {
                // 起点    
                refresh();
            }
        }

    调用的refresh()方法是AbstractApplicationContext的方法:(这个方法就像执行顺序图,描述好了先做什么,后做什么)

    public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                prepareRefresh();
    
                // Tell the subclass to refresh the internal bean factory. 这个步骤完成加载bean
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh();
    
                    // Check for listener beans and register them.
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();
    
                    // Reset 'active' flag.
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
            }
        }
    View Code

    obtainFreshBeanFactory()方法:

        protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
         // 这个方法是在AbstractApplicationContext定义没有实现的abstract方法,这就是所谓的模板模式吧,后面很多地方这样实现的,可以学习下。
            refreshBeanFactory();
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            if (logger.isDebugEnabled()) {
                logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
            }
            return beanFactory;
        }
    
      protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

    refreshBeanFactory()方法是谁实现的呢?子类去实现。AbstractRefreshableApplicationContext实现的:

        protected final void refreshBeanFactory() throws BeansException {
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }
            try {
           // 这里我们就看到了,通过这个方法调用来初始化的,都使用了DefaultListableBeanFactory作为IoC容器 DefaultListableBeanFactory beanFactory
    = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory);
           // 这个方法就去完成load Bean啦,不过它也使用了子类的实现 loadBeanDefinitions(beanFactory);
    synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }

    AbstractXmlApplicationContext实现的loadBeanDefinitions(DefaultListableBeanFactory beanFactory):

        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // Create a new XmlBeanDefinitionReader for the given BeanFactory.
         // 更深一层后,这里就开始定义了Reader是什么了。我们要读取的xml文件,这个Reader可以帮助我们
            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,
            // then proceed with actually loading the bean definitions.
            initBeanDefinitionReader(beanDefinitionReader);
         // 调用下面的的方法 loadBeanDefinitions(beanDefinitionReader); }
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) {
           // 把工作交给XmlBeanDefinitionReader完成 reader.loadBeanDefinitions(configLocations); } }

    通过XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader的方法把String configLocations封装成Recource,然后调用XmlBeanDefinitionReader实现的loadBeanDefinitions(resource)方法。

    下面是父类的调用方法:

        public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
            Assert.notNull(resources, "Resource array must not be null");
            int counter = 0;
         // 这里的for就可以理解多个xml文件的情况了
         // 从外面看,一个bean首先是放在多个xml中的一个,然后是一个xml文件中的多个bean描述中的一个,这个也是定位到一个bean要走的路。
    for (Resource resource : resources) {
           // 交给子类实现 counter
    += loadBeanDefinitions(resource); } return counter; }
    子类实现
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
            return loadBeanDefinitions(new EncodedResource(resource));
        }
    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()); }
             // 我觉得到这里,看方法名就知道了,要开始do了,前面好像都没do嘛
    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(); } } } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource);
           // 先解析成Document Document doc
    = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
           // 按照Spring的规则开始解析,放进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); } }

     XmlBeanDefinitionReader的registerBeanDefinitions方法:

        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            documentReader.setEnvironment(this.getEnvironment());
            int countBefore = getRegistry().getBeanDefinitionCount();
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }

    上面代码可以看到:继续交给DefaultBeanDefinitionDocumentReader来解析Document:

    下面是详细的处理过程:

        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
    
            logger.debug("Loading bean definitions");
            Element root = doc.getDocumentElement();
    
            doRegisterBeanDefinitions(root);
        }
        protected void doRegisterBeanDefinitions(Element root) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                Assert.state(this.environment != null, "environment property must not be null");
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!this.environment.acceptsProfiles(specifiedProfiles)) {
                    return;
                }
            }
    
            // 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 = createHelper(readerContext, root, parent);
    
            preProcessXml(root);
            parseBeanDefinitions(root, this.delegate);
            postProcessXml(root);
    
            this.delegate = parent;
        }
        protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            if (delegate.isDefaultNamespace(root)) {
                NodeList nl = root.getChildNodes();
           // 前面的注释中提到过bean定位时要从多个bean描述中一个个取,这个for循环就是了,
           //所以这个否循环里面的逻辑就是处理一个个bean的映射的,当然也有其他的标签,这里我们且认为只有bean吧
    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)) { // recurse ==>注意这个beans就递归,有调用了前面的doRegisterBeanDefinitions方法 doRegisterBeanDefinitions(ele); } }

     processBeanDefinition方法:

        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
         // 这里就出现了BeanDefinitionHolde 它封装了BeanDefinition
        // BeanDefinitionParserDelegate 来完成最底层的按照spring的规则解析
    BeanDefinitionHolder bdHolder
    = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.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)); } }
    parseBeanDefinitionElement方法的代码:
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
            String id = ele.getAttribute(ID_ATTRIBUTE);
            String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    
            List<String> aliases = new ArrayList<String>();
            if (StringUtils.hasLength(nameAttr)) {
                String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                aliases.addAll(Arrays.asList(nameArr));
            }
    
            String beanName = id;
            if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
                beanName = aliases.remove(0);
                if (logger.isDebugEnabled()) {
                    logger.debug("No XML 'id' specified - using '" + beanName +
                            "' as bean name and " + aliases + " as aliases");
                }
            }
    
            if (containingBean == null) {
                checkNameUniqueness(beanName, aliases, ele);
            }
    
            AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
            if (beanDefinition != null) {
                if (!StringUtils.hasText(beanName)) {
                    try {
                        if (containingBean != null) {
                            beanName = BeanDefinitionReaderUtils.generateBeanName(
                                    beanDefinition, this.readerContext.getRegistry(), true);
                        }
                        else {
                            beanName = this.readerContext.generateBeanName(beanDefinition);
                            // Register an alias for the plain bean class name, if still possible,
                            // if the generator returned the class name plus a suffix.
                            // This is expected for Spring 1.2/2.0 backwards compatibility.
                            String beanClassName = beanDefinition.getBeanClassName();
                            if (beanClassName != null &&
                                    beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                    !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                                aliases.add(beanClassName);
                            }
                        }
                        if (logger.isDebugEnabled()) {
                            logger.debug("Neither XML 'id' nor 'name' specified - " +
                                    "using generated bean name [" + beanName + "]");
                        }
                    }
                    catch (Exception ex) {
                        error(ex.getMessage(), ele);
                        return null;
                    }
                }
                String[] aliasesArray = StringUtils.toStringArray(aliases);
                return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
            }
    
            return null;
        }
    View Code

    上面解析的代码中有调用的一个方法parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)带我们去解析bean中更加详细的属性:

    public AbstractBeanDefinition parseBeanDefinitionElement(
                Element ele, String beanName, BeanDefinition containingBean) {
    
            this.parseState.push(new BeanEntry(beanName));
    
            String className = null;
            if (ele.hasAttribute(CLASS_ATTRIBUTE)) {// class属性 
                className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
            }
    
            try {
                String parent = null;
                if (ele.hasAttribute(PARENT_ATTRIBUTE)) {// parent属性
                    parent = ele.getAttribute(PARENT_ATTRIBUTE);
                }
                AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 下面parse方法解析其他的属性
                parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
                bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    
                parseMetaElements(ele, bd);
                parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
                parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    
                parseConstructorArgElements(ele, bd);
                parsePropertyElements(ele, bd);
                parseQualifierElements(ele, bd);
    
                bd.setResource(this.readerContext.getResource());
                bd.setSource(extractSource(ele));
    
                return bd;
            }
         // 下面的错误用spring有时候有看见过吧
    catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }

    以上就是解析好了,然后就是放进传说中的IoC容器里啦:

    BeanDefinitionReaderUtilsregisterBeanDefinition方法:

        public static void registerBeanDefinition(
                BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
                throws BeanDefinitionStoreException {
    
            // Register bean definition under primary name.
            String beanName = definitionHolder.getBeanName();
        // 调用了下BeanDefinitionRegistry 的方法,
        // 而这个registry就是DefaultListableBeanFactory,所有的BeanDefinition都要注册到它里面去呀...
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } }

    DefaultListableBeanFactory的registerBeanDefinition:

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionStoreException {
    
            Assert.hasText(beanName, "Bean name must not be empty");
            Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
            if (beanDefinition instanceof AbstractBeanDefinition) {
                try {
                    ((AbstractBeanDefinition) beanDefinition).validate();
                }
                catch (BeanDefinitionValidationException ex) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Validation of bean definition failed", ex);
                }
            }
            synchronized (this.beanDefinitionMap) {
                Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
           // 保证加载bean唯一性
    if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; }
           // 放到前面提到的ConcurrentHashMap里面去喽~
    this.beanDefinitionMap.put(beanName, beanDefinition); resetBeanDefinition(beanName); } }

    以上就是初始化IoC容器的过程。各位有兴趣可以自己debug进去一步步看既可以了。

    另外用maven的话直接用下面命令下载源码即可:

    mvn dependency:sources

    让我们继续前行

    ----------------------------------------------------------------------

    努力不一定成功,但不努力肯定不会成功。
    共勉。

  • 相关阅读:
    Leetcode 449. Serialize and Deserialize BST
    机器学习入门(1)------python基础
    Leetcode 23. Merge k Sorted Lists
    mysql explain执行计划详解
    ubuntu下安装chrome浏览器证书
    ubantu下配置android开发环境(Ubuntu 12.04.4 LTS x64 dell 3420)
    system v信号量的深入剖析
    AI文件格式解析
    STC12LE5A60S2第二串口出现的奇葩问题
    ZIGBEE官方协议栈 SampleApp工程DemoEB项目 运行机制详解
  • 原文地址:https://www.cnblogs.com/killbug/p/3250798.html
Copyright © 2011-2022 走看看