深入学习Spring源码---基本IOC容器初始化

基本容器:DefaultListableBeanFactory

BeanFactory:定义获取Bean及Bean的各种属性。

AutowireCapableBeanFactory:提供创建Bean、自动注入、初始化及应用Bean的后处理器。

ListableBeanFactory:根据各种条件获取Bean的配置清单。

HierarchicalBeanFactory:在BeanFactory的基础上增加了对parentFactory的支持。

ConfigurableBeanFactory:提供配置Factory的各种方法。

ConfigurableListableBeanFactory:BeanFactory的配置清单,指定忽略类型及接口等。

SingletonBeanRegistry:定义对单例的注册和获取。

AliasRegistry:定义对alias的简单增删改等操作。

BeanDefinitionRegistry:用map做缓存,并实现AliasRegistry接口。


容器初始化分为三个步骤:BeanDefinition的Resource定位、载入、和注册。

Bean的定义就是完整的描述了在Spring的配置文件中你定义的节点中所有的信息,包括各种子节点。当Spring成功解析你定义的一个节点后,在Spring的内部他就被转化 成BeanDefinition对象。以后所有的操作都是对这个对象完成的。

BeanDefinition:与配置文件中的<bean>中的属性是一一对应的。

GenericBeanDefinition:2.5版本后加的,一站式服务Bean。

RootBeanDefinition:父Bean是最常用的Bean。

ChildBeanDefinition:配置文件中可配置子Bean。

Resource定位:对不同来源的资源文件都有相应的Resource实现。文件、classPath、URL资源、Inputstream资源,Byte数组等。

Resource载入:通过持有*Loader(DefaultDocumentLoader)对象,来载入Resource资源获得Document对象。DocumentReader(DefaultBeanDefinitionDocumentReader)对象调用BeanDefinitionParserDelegate的相应方法,来解析Document对象得到BeanDefinitionHolder对象(持有BeanDefinition和与之相关的信息)。

BeanDefinition注册:通过持有BeanDefinitionRegistry对象,调用BeanDefinitionReaderUtils的registerBeanDefinition方法完成注册(加入一个Map缓存中)。


小结:

可以看到,Spring把初始化过程让三个不同模块一起组合完成,通过这样的方式,可以让用户更加灵活的进行裁剪和扩展。

源码跟踪:

1.ClassPathResource resource = new ClassPathResource("applicationContext.xml");
2.DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
3.XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
4.reader.loadBeanDefinitions(resource);

首先进入ClassPathResource类中:
public ClassPathResource(String path, ClassLoader classLoader) {
        Assert.notNull(path, "Path must not be null");
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        this.path = StringUtils.cleanPath(path);//路径问题
        this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
    }

由此可知,1只是判断路径和转换格式,返回Resource。
2也只是一个默认的构造方法,创建一个DefaultListableBeanFactory。
3构造方法中调用父类构造方法。
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        // Determine ResourceLoader to use.
        if (this.registry instanceof ResourceLoader) {
            this.resourceLoader = (ResourceLoader) this.registry;
        }
        else {
            this.resourceLoader = new PathMatchingResourcePatternResolver();
        }
    }
也只是初始化各种参数。
4是关键,首先XmlBeanDefinitionReader类中 :

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(new EncodedResource(resource));
    }

loadBeanDefinitions(EncodedResource encodedResource){
//主要代码段
InputStream inputStream = encodedResource.getResource().getInputStream();
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}


作用:对Resource编码封装。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource){

//主要代码段
//    获取对XML文件的验证模式

    int validationMode = getValidationModeForResource(resource);
// 加载XML文件,得到相应Document对象
             Document doc = this.documentLoader.loadDocument(
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
            return registerBeanDefinitions(doc, resource);
}


作用:得到Document对象,已完成Resource至Document的转换。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // Support old XmlBeanDefinitionParser SPI for backwards-compatibility.
        if (this.parserClass != null) {
            XmlBeanDefinitionParser parser =
                    (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
            return parser.registerBeanDefinitions(this, doc, resource);
        }
        // Read document based on new BeanDefinitionDocumentReader SPI.
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }


作用:实例化BeanDefinitionDocumentReader documentReader,调用它的registerBeanDefinitions方法。


现转至DefaultBeanDefinitionDocumentReader类中:

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;

        logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
//这个类专用于解析
        BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
//模板设计模式,解析前处理,留给子类实现
        preProcessXml(root);
        parseBeanDefinitions(root, delegate);
//解析后处理,留给子类实现        
postProcessXml(root);
    }

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
            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;
                    String namespaceUri = ele.getNamespaceURI();
                    if (delegate.isDefaultNamespace(namespaceUri)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }


作用:如果采用Spring默认的配置,则采用parseDefaultElement解析,否则采用delegate.parseCustomElement(ele)解析。

默认标签的解析:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
    }


对bean的解析:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        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));
        }
    }


作用:1委托BeanDefinitionParserDelegate的方法parseBeanDefinitionElement解析元素,返回BeanDefinitionHolder对象
2当返回的BeanDefinitionHolder对象不为空情况下若存在默认标签下再有自定义属性,还需再次对自定义标签进行解析。
3完成解析后,调用BeanDefinitionReaderUtils的registerBeanDefinition方法完成注册
4发出响应事件,通知相关的监听器,这个bean已加载完成。


现转至BeanDefinitionParserDelegate类中:解析各种属性
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        List aliases = new ArrayList();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            beanName = (String) 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;
    }

public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, BeanDefinition containingBean) {

        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {
            this.parseState.push(new BeanEntry(beanName));

            AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(
                    parent, className, this.readerContext.getBeanClassLoader());

            if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
                // Spring 2.x "scope" attribute
                bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
                if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
                    error("Specify either 'scope' or 'singleton', not both", ele);
                }
            }
            else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
                // Spring 1.x "singleton" attribute
                bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ?
                        BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);
            }
            else if (containingBean != null) {
                // Take default from containing bean in case of an inner bean definition.
                bd.setScope(containingBean.getScope());
            }

            if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
                bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
            }

            String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
            if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton()) {
                // Just apply default to singletons, as lazy-init has no meaning for prototypes.
                lazyInit = this.defaults.getLazyInit();
            }
            bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

            String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
            bd.setAutowireMode(getAutowireMode(autowire));

            String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
            bd.setDependencyCheck(getDependencyCheck(dependencyCheck));

            if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
                String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
                bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, BEAN_NAME_DELIMITERS));
            }

            String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
            if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
                String candidatePattern = this.defaults.getAutowireCandidates();
                if (candidatePattern != null) {
                    String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
                    bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
                }
            }
            else {
                bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
            }

            if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
                bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
            }

            if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
                String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
                if (!"".equals(initMethodName)) {
                    bd.setInitMethodName(initMethodName);
                }
            }
            else {
                if (this.defaults.getInitMethod() != null) {
                    bd.setInitMethodName(this.defaults.getInitMethod());
                    bd.setEnforceInitMethod(false);
                }
            }

            if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
                String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
                if (!"".equals(destroyMethodName)) {
                    bd.setDestroyMethodName(destroyMethodName);
                }
            }
            else {
                if (this.defaults.getDestroyMethod() != null) {
                    bd.setDestroyMethodName(this.defaults.getDestroyMethod());
                    bd.setEnforceDestroyMethod(false);
                }
            }

            if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
                bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
            }
            if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
                bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
            }

            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;
        }
        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;
    }
注:解析元素非常繁琐,就不细细看了。

public static AbstractBeanDefinition createBeanDefinition(
            String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {

        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setParentName(parentName);
        if (className != null) {
            if (classLoader != null) {
                bd.setBeanClass(ClassUtils.forName(className, classLoader));
            }
            else {
                bd.setBeanClassName(className);
            }
        }
        return bd;
    }

作用:创建BeanDefinition,调用BeanDefinitionReaderUtils的registerBeanDefinition方法完成注册


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 (int i = 0; i < aliases.length; i++) {
                registry.registerAlias(beanName, aliases[i]);
            }
        }
    }

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "'beanName' 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);
            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;
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
//重置所有beanName对应缓存
            resetBeanDefinition(beanName);
        }

    }


public void registerAlias(String name, String alias) {
        Assert.hasText(name, "'name' must not be empty");
        Assert.hasText(alias, "'alias' must not be empty");
        if (alias.equals(name)) {
            this.aliasMap.remove(alias);
        }
        else {
            if (!allowAliasOverriding()) {
                String registeredName = (String) this.aliasMap.get(alias);
                if (registeredName != null && !registeredName.equals(name)) {
                    throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                            name + "': It is already registered for name '" + registeredName + "'.");
                }
            }
            this.aliasMap.put(alias, name);
        }
    }


 至此,IOC的初始化,配置文件就被加载到BeanFactory中。 
 






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值