zoukankan      html  css  js  c++  java
  • 2. spring中IOC的实现源码篇【analyze spring framework source】

    2B青年欢乐多啊,最近研究spring源码,做点笔记,欢迎继续补充, 持续更新

    接上一篇 1. Introduce how to import the Spring Framework sourcecode into an eclipse project

    一. 结构

    spring中bean管理设计到下面3个包

    image

    core 相当于一个工具类,bean包是对IOC的实现包,context是在bean的基础扩展功能

    IOC的实现原理简介

    简单实现

    package org.benson;
    
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
    import org.springframework.core.io.ClassPathResource;
    
    public class Test4DebugSpringIOC {
        ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();//manage bean factory
        ClassPathResource resource = new ClassPathResource(
                "applicationContext.xml");//resource
        XmlBeanDefinitionReader xmlReader=new XmlBeanDefinitionReader((BeanDefinitionRegistry)beanFactory); //register
        
        public Test4DebugSpringIOC() {
            // TODO load and registered BeanDefinition
            xmlReader.loadBeanDefinitions(resource);
        }
        public static void main(String[] args) {
            Test4DebugSpringIOC test4DebugSpring= new Test4DebugSpringIOC();
            Test4DebugSpringBean test4DebugSpringBean = (Test4DebugSpringBean) test4DebugSpring.beanFactory
                    .getBean("testAlias");
            test4DebugSpringBean.SayHolle();
        }
    }

     1,找到bean的定义文件(Resource)

          如此处classPathResource,用于找到文件位置

     2,把定义文件解析成BeanDefinition对象并进行注册,在XmlBeanDefinitionReader中

                int validationMode = getValidationModeForResource(resource);//Validation xml file  . XmlBeanDefinitionReader doLoadBeanDefinitions
                Document doc = this.documentLoader.loadDocument(
                        inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());//parse to doc . through documentLoader(DefaultDocumentLoader)
                return registerBeanDefinitions(doc, resource);

    一个普通bean的解析step 

     i 调用DefaultDocumentLoader把XML解析成DOC并进行XSD,DTD等格式验证.

     DefaultDocumentLoader调用了SAX的DocumentBuilderFactory.newInstance(),把XML文件解析成一个org.w3c.dom.Document对象(标准的DOM解析方式),当然也设置XML验证的validationMode,namespace

        /**
         * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
         * XML parser.
         */
        public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
                ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
    
            DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
            if (logger.isDebugEnabled()) {
                logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
            }
            DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
            return builder.parse(inputSource);
        }

    ii DefaultBeanDefinitionDocumentReader读取document中的所有Element. 

    registerBeanDefinitions(doc, resource)中调用BeanDefinitionDocumentReader的registerBeanDefinitions方法获根节点

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    		this.readerContext = readerContext;
    
    		logger.debug("Loading bean definitions");
    		Element root = doc.getDocumentElement();
    
    		doRegisterBeanDefinitions(root);
    	}
    

    得到XML的根节点,调用doRegisterBeanDefinitions

        /**
         * Register each bean definition within the given root {@code <beans/>} element.
         * @throws IllegalStateException if {@code <beans profile="..."} attribute is present
         * and Environment property has not been set
         * @see #setEnvironment
         */
        protected void doRegisterBeanDefinitions(Element root) {
    ..//profile
    
            // 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;
        }

    然后从获得根结点的所有子节点,进行循环

        /**
         * Parse the elements at the root level in the document:
         * "import", "alias", "bean".
         * @param root the DOM root element of the document
         */
        protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            if (delegate.isDefaultNamespace(root)) {
                NodeList nl = root.getChildNodes();
                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);//parse defalut element
                        }
                        else {
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            }
            else {
                delegate.parseCustomElement(root);
            }
        }

     此处isDefaultNamespace方法是获取namespace为http://www.springframework.org/schema/beans的node,目前对应schema定义的包括"bean" "alis" "beans" "import" ,处理方法为parseDefaultElement(ele, delegate),如果发现是bean标签则调用processBeanDefinition方法

        /**
         * Process the given bean element, parsing the bean definition
         * and registering it with the registry.
         */
        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //parse to object of BeanDefinitionHolder
            if (bdHolder != null) {//if it is not exit. parse it from xml
                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));
            }
        }

    iii 调用BeanDefinitionParserDelegate对象完成doc中Element->BeanDefinitionHolder的转换

        /**
         * Parses the supplied <code>&lt;bean&gt;</code> element. May return <code>null</code>
         * if there were errors during parse. Errors are reported to the
         * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
         */
        public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
            String id = ele.getAttribute(ID_ATTRIBUTE);
            String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    ... ... //vacation
            AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    ....
    
    return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
            }

    先获得别名,这里叫nameAttr先转成数组,然后通过BeanDefinitionHolder把它和beanName,beandefine绑定在一起

    /**
         * Parse the bean definition itself, without regard to name or aliases. May return
         * <code>null</code> if problems occurred during the parsing of the bean definition.
         */
        public AbstractBeanDefinition parseBeanDefinitionElement(
                Element ele, String beanName, BeanDefinition containingBean) {
    
            this.parseState.push(new BeanEntry(beanName));
    
            String className = null;
            if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
                className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
            }
    
            try {
                String parent = null;
                if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                    parent = ele.getAttribute(PARENT_ATTRIBUTE);
                }
                AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    
                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;
            }

    全部当成属性设置到了AbstractBeanDefinition 的对象中,具体可以看AbstractBeanDefinition 类

    最后返回BeanDefinitionHolder;BeanDefinitionHolder是由beanname+aliasArray+beandefinition组成的一个对象

    IV 然后回到ii的最后调用BeanDefinitionReaderUtils.registerBeanDefinition注册beandefine对象,并调BeanDefinitionRegistry接口进行注册,如DefaultListableBeanFactory

    完成转换后,BeanDefinitionReaderUtils.registerBeanDefinition 调用到 BeanDefinitionRegistry接口实现类的registerBeanDefinition方法把对象放入bean的工厂容器中

         * Register the given bean definition with the given bean factory.
         * @param definitionHolder the bean definition including name and aliases
         * @param registry the bean factory to register with
         * @throws BeanDefinitionStoreException if registration failed
         */
        public static void registerBeanDefinition(
                BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
                throws BeanDefinitionStoreException {
    
            // Register bean definition under primary name.
            String beanName = definitionHolder.getBeanName();
            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的实现也很简单了,直接用map添加下就OK了

        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionStoreException {
    ....//Validation
    
                this.beanDefinitionMap.put(beanName, beanDefinition);//add it to beanDefinitionMap
            }
    
            resetBeanDefinition(beanName); //reset all exist
        }

     3,查找,通过getbean获得bean,用ConfigurableListableBeanFactory,如DefaultListableBeanFactory

    这部分功能主要在abstractbeanfactory中完成,如果是singleton(即spring的default)

    i   transformedBeanName(name) ,得到SimpleAliasRegistry 的 map 属性 aliasMap,转换为beanname(别名功能)

    ii  Object sharedInstance = getSingleton(beanName); 尝试从DefaultSingletonBeanRegistry的MAP singletonObjects中拿出bean (singleton功能)

    iii  bean = getObjectForBeanInstance(sharedInstance, name, beanName, null) 处理factorybean部分,附 Spring FactoryBean源码浅析

    iv final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 从bean注册的信息中找到bean 对应的 BeanDefinition

    v return createBean(beanName, mbd, args); 创建新的bean,通过BeanDefinition的描述信息来,并填充到DefaultSingletonBeanRegistry的singletonObjects中

    beanfactory的主要代码,加上了些注释

        /**
         * Return an instance, which may be shared or independent, of the specified bean.
         * @param name the name of the bean to retrieve
         * @param requiredType the required type of the bean to retrieve
         * @param args arguments to use if creating a prototype using explicit arguments to a
         * static factory method. It is invalid to use a non-null args value in any other case.
         * @param typeCheckOnly whether the instance is obtained for a type check,
         * not for actual use
         * @return an instance of the bean
         * @throws BeansException if the bean could not be created
         */
        @SuppressWarnings("unchecked")
        protected <T> T doGetBean(
                final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
                throws BeansException {
            final String beanName = transformedBeanName(name); //get true name from attribute aliasMap of SimpleAliasRegistry
            Object bean;
            // Eagerly check singleton cache for manually registered singletons.
            Object sharedInstance = getSingleton(beanName); //get instance object from the attribute singletonObjects of DefaultSingletonBeanRegistry
            if (sharedInstance != null && args == null) {
                if (logger.isDebugEnabled()) {
                    if (isSingletonCurrentlyInCreation(beanName)) {
                        logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                                "' that is not fully initialized yet - a consequence of a circular reference");
                    }
                    else {
                        logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                    }
                }
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); // it is for that class witch is implement interface factorybean
            }
    
            else {
                // Fail if we're already creating this bean instance:
                // We're assumably within a circular reference.
                if (isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }
    
                // Check if bean definition exists in this factory.
                BeanFactory parentBeanFactory = getParentBeanFactory();
                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                    // Not found -> check parent.
                    String nameToLookup = originalBeanName(name);
                    if (args != null) {
                        // Delegation to parent with explicit args.
                        return (T) parentBeanFactory.getBean(nameToLookup, args);
                    }
                    else {
                        // No args -> delegate to standard getBean method.
                        return parentBeanFactory.getBean(nameToLookup, requiredType);
                    }
                }
    
                if (!typeCheckOnly) {
                    markBeanAsCreated(beanName);
                }
    
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//get BeanDefinition from registered information
                checkMergedBeanDefinition(mbd, beanName, args);
    
                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dependsOnBean : dependsOn) {
                        getBean(dependsOnBean);
                        registerDependentBean(dependsOnBean, beanName);
                    }
                }
    
                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        //create new instance and put in attribute map singletonObjects of DefaultSingletonBeanRegistry
                        public Object getObject() throws BeansException {
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            catch (BeansException ex) {
                                // Explicitly remove instance from singleton cache: It might have been put there
                                // eagerly by the creation process, to allow for circular reference resolution.
                                // Also remove any beans that received a temporary reference to the bean.
                                destroySingleton(beanName);
                                throw ex;
                            }
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
    
                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }
    
                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                            public Object getObject() throws BeansException {
                                beforePrototypeCreation(beanName);
                                try {
                                    return createBean(beanName, mbd, args);
                                }
                                finally {
                                    afterPrototypeCreation(beanName);
                                }
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; " +
                                "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
    
            // Check if required type matches the type of the actual bean instance.
            if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
                try {
                    return getTypeConverter().convertIfNecessary(bean, requiredType);
                }
                catch (TypeMismatchException ex) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Failed to convert bean '" + name + "' to required type [" +
                                ClassUtils.getQualifiedName(requiredType) + "]", ex);
                    }
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
            }
            return (T) bean;
        }

    附 bean中的主要结构

    主要类,下列类从上往下继承

    SimpleAliasRegistry 用于维护一个 aliasMap,维护别名功能

    DefaultSingletonBeanRegistry map 维护 singletonObjects,维护工厂单例,一个工厂一个单例,非N个工厂一个单例

    FactoryBeanRegistrySupport

    AbstractBeanFactory ,factorybean的主要实现类,其doGetBean,getBean是主要获得bean的入口 ,维护一个mergedBeanDefinitions

    AbstractAutowireCapableBeanFactory,configureableBeanFactory的主要实现类,  createBean根据beandefine的信息创建相应的值

    DefaultListableBeanFactory ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的主要实现类,维护beanDefiniti信息

    主要接口关系如下

    image

    Parse XML主要用到的几个相关类

    * @see DocumentLoader
    * @see DefaultDocumentLoader

    TODO 对SAX几个工厂属性进行设置,schema等,调用SAX对XML转换成了DOC对象

    * @see BeanDefinitionDocumentReader  
    * @see DefaultBeanDefinitionDocumentReader

    提供registerBeanDefinitions,和setEnvironment方法,用于DOC到beandefine的注册功能,遍历了doc的所有node,调用 BeanDefinitionParserDelegate解析node,并调用BeanDefinitionReaderUtils对解析的beandefine到beandefine注册类的注册

    * @BeanDefinitionParserDelegate

    主要解析类,各种属性,对beandefine对象属性的设置都是在此类完成

    bean中ConfigurableListableBeanFactory接口继承了bean中的基本接口,DefaultListableBeanFactory是其唯一实现类,也是预留接口供扩展

    接口因为可以多继承,所以用来表示系统的结构最合适不过,而JAVA中类单继承的,一般只是用来实现设计,侧重实现功能,因为类层次肯定是一条线。

  • 相关阅读:
    Markdown基础语法
    Java是什么
    myBatis框架_关于怎么获得多表查询的总记录数
    关于Could not load driverClass ${jdbc.driverClassName}问题解决方案
    java中String与StringBuffer拼接的区别
    部分标签
    基础标签 网页分类
    入坑小开头
    完整版的OpenLDAP搭建全过程
    测试Linux下tcp最大连接数限制
  • 原文地址:https://www.cnblogs.com/springsource/p/2873365.html
Copyright © 2011-2022 走看看