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中類單繼承的,一般只是用來實現設計,側重實現功能,因為類層次肯定是一條線。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM