美文网首页程序员
Spring容器初始化之配置信息解析

Spring容器初始化之配置信息解析

作者: 小螺钉12138 | 来源:发表于2018-08-19 19:53 被阅读0次

    Spring 容器初始化

    初始化代码

     @Test
        public void testInit2(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans.xml");
            Car car= (Car) context.getBean("car");
            System.out.println(car.getBrand());
        }
    

    ClassPathXmlApplicationContext代码结构图


    SpringIOC容器初始化代码结构图

    ClassPathXmlApplicationContext初始化代码

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                throws BeansException {
    
            super(parent);
            //解析配置文件,例如(多个配置文件路径解析成字符串数组,将路径前后的空格去掉)
            setConfigLocations(configLocations);
            if (refresh) {
            //Spring IOC容器初始化的核心方法
                refresh();
            }
        }
    

    核心方法refresh()代码解析

    public void refresh() throws BeansException, IllegalStateException {
            //此处增加Synchronized字段,给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作
            synchronized (this.startupShutdownMonitor) {
                //refresh容器时的一些准备工作,设置容器的状态(close设置为false,active设置为true)
                prepareRefresh();
                //重点方法:
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                //准备 Bean 容器: prepareBeanFactory
                prepareBeanFactory(beanFactory);
    
                try {
                    // 允许子类这册子自定义的后置处理器
                    postProcessBeanFactory(beanFactory);
    
                    // 调用子类的后置处理器
                    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) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();
    
                    // Reset 'active' flag.
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
            }
        }
    
    

    obtainFreshBeanFactory()方法解析【refresh中核心方法】

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
            //如果有旧的BeanFactory则销毁旧的BeanFactory,然后创建一个新的BeanFactory,加载Bean、注册Bean等等
            refreshBeanFactory();
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            if (logger.isDebugEnabled()) {
                logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
            }
            return beanFactory;
        }
        
    
    //refreshBeanFactory()方法代码解析
    protected final void refreshBeanFactory() throws BeansException {
            //如果有BeanFactory,销毁和关闭BeanFactory
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }
            try {
                //创建一个DefaultListableBeanFactory对象
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                //设置beanFactory的的序列化ID
                beanFactory.setSerializationId(getId());
                //定义BeanFactory的属性(Bean可覆盖,Bean循环引用)
                customizeBeanFactory(beanFactory);
                //加载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);
            }
        }
        
    

    BeanDefinition 的覆盖问题可能会有开发者碰到这个坑,就是在配置文件中定义 bean 时使用了相同的 id 或 name,默认情况下,allowBeanDefinitionOverriding 属性为 null,如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖

    为什么使用DafaultListableBeanFactory初始化BeanFactory


    BeanFactory代码结构

    从上图可以看出DefaultListableBeanFactory类和所有的BeanFactory类或者接口都有关系,因此这个类是最强大的BeanFactory。

    加载 Bean: loadBeanDefinitions。这个方法根据配置加载各个Bean,然后将Bean放置到BeanFactory中。读取配置的操作在 XmlBeanDefinitionReader 中,其负责加载配置、解析。

    /**
         * Loads the bean definitions via an XmlBeanDefinitionReader.
         */
        @Override
        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // 为BeanFacotry创建一个获取Bean信息的XmlBeanDefinitionReader对象
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
            //给XmlBeanDefinitionReader配置上下文的资源环境
            beanDefinitionReader.setEnvironment(this.getEnvironment());
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        
            //允许子类提供自定义初始化BeanFactory的reader
            // Allow a subclass to provide custom initialization of the reader,
            // then proceed with actually loading the bean definitions.
            //初始化加载Bean definitions的Reader,默认的实现是空的(让子类提供定制的初始化)
            initBeanDefinitionReader(beanDefinitionReader);
            //加载BeanDefinitionReader
            loadBeanDefinitions(beanDefinitionReader);
        }
    
    

    加载BeanDefinitionReader的加载方法loadBeanDefinitions

    /**
         *通过XmlBeanDefinitionReader加载bean definitions,bean *factory的生命周期通过refreshBeanFactory方法来处理。这个方法应该来加*载或者注册bean definitions
         */
        protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        //以Resources的方式获取配置文件的资源位置
            Resource[] configResources = getConfigResources();
            if (configResources != null) {
                reader.loadBeanDefinitions(configResources);
            }
        //以String的形式获取配置文件的位置
            String[] configLocations = getConfigLocations();
            if (configLocations != null) {
                reader.loadBeanDefinitions(configLocations);
            }
        }
    

    无论是上面获取的是Resource还是String形式的资源地址,最后加载资源的加载方法都是下面的loadBeanDefinitions方法

    /**
         * 从特别的xml文件来加载bean definition
         */
        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());
            }
            //用ThreadLocal来存放当前的资源
            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 {
            //将Resource转换成XML实体的单一输入源InputSource
                InputStream inputStream = encodedResource.getResource().getInputStream();
                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    //处理InputSource的方法
                    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();
                }
            }
        }
    

    处理inputSource的doLoadBeanDefinitions方法

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
            try {
                //将inputSource转换成Document对象
                Document doc = doLoadDocument(inputSource, resource);
                //下面方法是对BeanDefinition解析的详细过程,这个解析会使用到Spring的Bean配置规则
                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);
            }
        }
    

    加载Spring Bean的方法registerBeanDefinitions解析

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            //这里得到BeanDefinitionDocumentReader来对XML的BeanDefinition进行解析
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            documentReader.setEnvironment(getEnvironment());
            int countBefore = getRegistry().getBeanDefinitionCount();
            //具体的解析过程在这个registerBeanDefinitions中完成
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }
        
    /**
         *根据Spring-beans的XSD来解析bean definitions
         */
        @Override
        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            logger.debug("Loading bean definitions");
            Element root = doc.getDocumentElement();
            //从xml根节点来解析
            doRegisterBeanDefinitions(root);
        }
        
    /**
         * 
         * 通过给定的root来注册每个定义的bean
         */
        protected void doRegisterBeanDefinitions(Element root) {
        //通过BeanDefinitionParserDelegate类来解析Bean定义
            BeanDefinitionParserDelegate parent = this.delegate;
        //这里为什么要定义一个 parent? 看到后面就知道了,是递归问题,
       // 因为 <beans /> 内部是可以定义 <beans /> 的,所以这个方法的 root 其实不一定就是 xml 的根节点,也可以是嵌套在里面的 <beans /> 节点,从源码分析的角度,我们当做根节点就好了
            this.delegate = createDelegate(getReaderContext(), root, parent);
    
            if (this.delegate.isDefaultNamespace(root)) {
            // 这块说的是根节点 <beans ... profile="dev" /> 中的 profile 是否是当前环境需要的,
          // 如果当前环境配置的 profile 不包含此 profile,那就直接 return 了,不对此 <beans /> 解析
                String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
                if (StringUtils.hasText(profileSpec)) {
                    String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                            profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                    if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                        return;
                    }
                }
            }
    
            //钩子方法
            preProcessXml(root);
            //重点方法
            parseBeanDefinitions(root, this.delegate);
            //钩子方法
            postProcessXml(root);
            this.delegate = parent;
        }
        
        /**
         * 解析document中的标签如下
         * "import", "alias", "bean".
         */
        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)) {
                        //处理默认的namespace
                            parseDefaultElement(ele, delegate);
                        }
                        else {
                        //处理其他的namespace
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            }
            else {
                delegate.parseCustomElement(root);
            }
        }
    
    /**
     *处理默认的namespace
     *
     */
    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
            if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            //处理import标签
                importBeanDefinitionResource(ele);
            }
            else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            //处理alias标签
                processAliasRegistration(ele);
            }
            else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            //处理bean标签
                processBeanDefinition(ele, delegate);
            }
            else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
                // 如果是嵌套beans标签,采用递归方式解析
                doRegisterBeanDefinitions(ele);
            }
        }
    
    

    这里具体解析处理bean标签的解析器,processBeanDefinition方法分析

    /**
         *解析bean definition然后注册
         */
        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //将bean中的信息提取出来,封装到一个BeanDefinitionHolder对象中
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
            if (bdHolder != null) {
                bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
                try {
                    //注册最后的装饰实例(封装完成的BeanDefinition)
                    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
                }
                catch (BeanDefinitionStoreException ex) {
                    getReaderContext().error("Failed to register bean definition with name '" +
                            bdHolder.getBeanName() + "'", ele, ex);
                }
                //发送注册事件
                getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
            }
        }
        
        /**
         *解析bean标签中的信息,然后将信息封装进BeanDefinitionHolder对象中 
         */
        public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
            //获取id的属性值
            String id = ele.getAttribute(ID_ATTRIBUTE);
            //获取name的属性值
            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;
        }
        
    
        /**
         * 创建beanDefinition实例
         */
        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));
    
                // 解析 <meta />
                parseMetaElements(ele, bd);
                // 解析 <lookup-method />
                parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
                // 解析 <replaced-method />
                parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
                // 解析 <constructor-arg />
                parseConstructorArgElements(ele, bd);
                // 解析 <property />
                parsePropertyElements(ele, bd);
                // 解析 <qualifier />
                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;
        }
    

    bean标签解析成功之后,进行注册

    /**
         *
         * 鉴于bean factory来注册bean definition
         */
        public static void registerBeanDefinition(
                BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
                throws BeanDefinitionStoreException {
    
            // 注册bean使用最原始的名称
            String beanName = definitionHolder.getBeanName();
            registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
            // 如果有别名就使用别名来注册
            String[] aliases = definitionHolder.getAliases();
            if (aliases != null) {
                for (String alias : aliases) {
                    registry.registerAlias(beanName, alias);
                }
            }
        }
        
    //注册别名
    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);
                }
            }
    
            BeanDefinition oldBeanDefinition;
            //查看beanName名称是否被注册
            oldBeanDefinition = this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) {
            //如果beanName名称已经被注册过,并且没有bean覆盖标识则抛出异常
                if (!isAllowBeanDefinitionOverriding()) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
                }
                else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                    // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                                "' with a framework-generated bean definition: replacing [" +
                                oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
                else {
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding bean definition for bean '" + beanName +
                                "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
            }
            else {
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
                this.frozenBeanDefinitionNames = null;
            }
            //所有的bean信息都会放进该map中,这个map用来保存所有的beanDefinition信息
            this.beanDefinitionMap.put(beanName, beanDefinition);
    
            if (oldBeanDefinition != null || containsSingleton(beanName)) {
                resetBeanDefinition(beanName);
            }
        }
    

    ==总结==:到了当前的阶段,xml中的Bean信息已经被解析完毕,Bean容器已经被初始化。Bean标签中的相关配置也装换成相应的BeanDefinition对象,已经注册到BeanDefinition中心,注册事件也已经发布成功。

    相关文章

      网友评论

        本文标题:Spring容器初始化之配置信息解析

        本文链接:https://www.haomeiwen.com/subject/xxchiftx.html