zoukankan      html  css  js  c++  java
  • IOC容器初始化

    参考:https://www.cnblogs.com/ITtangtang/p/3978349.html

    一、Ioc/DI

      控制反转,把原先代码里需要实现的对象的创建、依赖的代交给容器帮忙实现。所以需要创建一个容器,同时需要一种描述让容器知道需要创建的对象与对象之间的关系。

      对象与对象之间的关系通过 xml, properties 文件等语义化配置文件表示。文件存放位置:类路径,文件系统,URL,servletContext等。

      不同的配置文件对对象的描述不一样,所以内部需要一个统一的关于对象的定义,即BeanDefinition。解析的话需要不同的解析器。

    二、Spring IOC 体系结构

      BeanFactory: 最顶层的接口类,定义了IOC容器的基本功能规范。

      ApplicationContext:高级的IOC容器,额外实现了其他功能,如:支持信息源(实现MessageSource接口),访问资源,支持应用事件。

    三、IoC容器的初始化

    1. BeanDefinition的Resource定位
    2. BeanDefinition的载入
    3. BeanDefinition的注册


    1、XmlBeanFactory的创建过程

    //根据Xml配置文件创建Resource资源对象,该对象中包含了BeanDefinition的信息
     ClassPathResource resource =new ClassPathResource("application-context.xml");
    //创建DefaultListableBeanFactory
     DefaultListableBeanFactory factory =new DefaultListableBeanFactory();
    //创建XmlBeanDefinitionReader读取器,用于载入BeanDefinition。之所以需要BeanFactory作为参数,是因为会将读取的信息回调配置给factory
     XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory);
    //XmlBeanDefinitionReader执行载入BeanDefinition的方法,最后会完成Bean的载入和注册。完成后Bean就成功的放置到IOC容器当中,以后我们就可以从中取得Bean来使用
     reader.loadBeanDefinitions(resource);

    步骤:

    • 根据Xml配置文件创建Resource资源对象
    • 创建DefaultListableBeanFactory
    • 创建XmlBeanDefinitionReader读取器,用于载入BeanDefinition,需要Factory作为参数
    • 调用loadBeanDefinitions(Resource)

    2、ApplicationContext的创建过程

    1. 设置资源加载器(即容器本身)

    2. 设置好Location

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  
                throws BeansException {    
            super(parent);  //调用父类构造器方法设置好资源加载器
            setConfigLocations(configLocations);  //setConfigLocations("a.xml") 设置好 Resource
            if (refresh) {  
                refresh();  //重建IOC容器,并进行初始化
            }  
        }
    public void refresh() throws BeansException, IllegalStateException {  
           synchronized (this.startupShutdownMonitor) {  
               //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识  
               prepareRefresh();  
               //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从  
              //子类的refreshBeanFactory()方法启动  
               ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
               //为BeanFactory配置容器特性,例如类加载器、事件处理器等  
               prepareBeanFactory(beanFactory);  
               try {  
                   //为容器的某些子类指定特殊的BeanPost事件处理器  
                   postProcessBeanFactory(beanFactory);  
                   //调用所有注册的BeanFactoryPostProcessor的Bean  
                   invokeBeanFactoryPostProcessors(beanFactory);  
                   //为BeanFactory注册BeanPost事件处理器.  
                   //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件  
                   registerBeanPostProcessors(beanFactory);  
                   //初始化信息源,和国际化相关.  
                   initMessageSource();  
                   //初始化容器事件传播器.  
                   initApplicationEventMulticaster();  
                   //调用子类的某些特殊Bean初始化方法  
                   onRefresh();  
                   //为事件传播器注册事件监听器.  
                   registerListeners();  
                   //初始化所有剩余的单态Bean.  
                   finishBeanFactoryInitialization(beanFactory);  
                   //初始化容器的生命周期事件处理器,并发布容器的生命周期事件  
                   finishRefresh();  
               }  
               catch (BeansException ex) {  
                   //销毁以创建的单态Bean  
                   destroyBeans();  
                   //取消refresh操作,重置容器的同步标识.  
                   cancelRefresh(ex);  
                   throw ex;  
               }  
           }  
       }

    3. 创建BeanFactory,具体是调用子类refreshBeanFactory()方法

    4. 子类的refreshBeanFactory()方法

    • 创建容器 DefaultListableBeanFactory,完成一些配置,如初始化启动参数,开启注解的自动装配
    • 启动载入Bean定义资源的过程
    protected final void refreshBeanFactory() throws BeansException {  
           if (hasBeanFactory()) {//如果已经有容器,销毁容器中的bean,关闭容器  
               destroyBeans();  
               closeBeanFactory();  
           }  
           try {  
                //创建IoC容器  
                DefaultListableBeanFactory beanFactory = createBeanFactory();  
                beanFactory.setSerializationId(getId());  
               //对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等  
               customizeBeanFactory(beanFactory);  
               //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器  
               loadBeanDefinitions(beanFactory);  
               synchronized (this.beanFactoryMonitor) {  
                   this.beanFactory = beanFactory;  
               }  
           }  
           catch (IOException ex) {  
               throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);  
           }  
       }

    子类的loadBeanDefinition()实现

    • 创建XmlBeanDefinitionReader,通过回调设置到容器中
    • 为读取器设置资源加载器,就是之前设置好的容器本身
    • 为读取器设置xml解析器
    • loadBeanDefinition(Reader)实现真正的加载,执行reader.loadBeanDefinitions(configLocations)分支
    public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {  
        ……  
        //实现父类抽象的载入Bean定义方法  
        @Override  
        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {  
            //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源  
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
            //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的  
            //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器  
           beanDefinitionReader.setResourceLoader(this);  
           //为Bean读取器设置SAX xml解析器  
           beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
           //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制  
           initBeanDefinitionReader(beanDefinitionReader);  
           //Bean读取器真正实现加载的方法  
           loadBeanDefinitions(beanDefinitionReader);  
       }  
       //Xml Bean读取器加载Bean定义资源  
       protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  
           //获取Bean定义资源的定位  
           Resource[] configResources = getConfigResources();  
           if (configResources != null) {  
               //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位  
               //的Bean定义资源  
               reader.loadBeanDefinitions(configResources);  
           }  
           //如果子类中获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源  
           String[] configLocations = getConfigLocations();  
           if (configLocations != null) {  
               //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位  
               //的Bean定义资源  
               reader.loadBeanDefinitions(configLocations);  
           }  
       }  
       //这里又使用了一个委托模式,调用子类的获取Bean定义资源定位的方法  
       //该方法在ClassPathXmlApplicationContext中进行实现,对于我们  
       //举例分析源码的FileSystemXmlApplicationContext没有使用该方法  
       protected Resource[] getConfigResources() {  
           return null;  
       }   ……  
    }

    loadBeanDefinitions(configLocations)方法也是类似的

    • 设置资源加载器
    • resourceLoader.getResource(location)获取Resource
    • 委派子类XmlBeanDefinitionReader的loadBeanDefinitions方法
    //重载方法,调用下面的loadBeanDefinitions(String, Set<Resource>);方法  
       public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {  
           return loadBeanDefinitions(location, null);  
       }  
       public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {  
           //获取在IoC容器初始化过程中设置的资源加载器  
           ResourceLoader resourceLoader = getResourceLoader();  
           if (resourceLoader == null) {  
               throw new BeanDefinitionStoreException(  
                       "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");  
           }  
           if (resourceLoader instanceof ResourcePatternResolver) {  
               try {  
                   //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                   //加载多个指定位置的Bean定义资源文件  
                   Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);  
                   //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能  
                   int loadCount = loadBeanDefinitions(resources);  
                   if (actualResources != null) {  
                       for (Resource resource : resources) {  
                           actualResources.add(resource);  
                       }  
                   }  
                   if (logger.isDebugEnabled()) {  
                       logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");  
                   }  
                   return loadCount;  
               }  
               catch (IOException ex) {  
                   throw new BeanDefinitionStoreException(  
                           "Could not resolve bean definition resource pattern [" + location + "]", ex);  
               }  
           }  
           else {  
               // 调用DefaultResourceLoader的getResource完成具体的Resource定位
               Resource resource = resourceLoader.getResource(location);  
               //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能  
               int loadCount = loadBeanDefinitions(resource);  
               if (actualResources != null) {  
                   actualResources.add(resource);  
               }  
               if (logger.isDebugEnabled()) {  
                   logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");  
               }  
               return loadCount;  
           }  
       }  
       //重载方法,调用loadBeanDefinitions(String);  
       public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {  
           Assert.notNull(locations, "Location array must not be null");  
           int counter = 0;  
           for (String location : locations) {  
               counter += loadBeanDefinitions(location);  
           }  
           return counter;  
        }

    这里分析下DefaultResourceLoader的getResource方法

    • 对路径进行解析,生成对应的URLResoucer、ClassPathResource...对象
    //获取Resource的具体实现方法  
       public Resource getResource(String location) {  
           Assert.notNull(location, "Location must not be null");  
           //如果是类路径的方式,那需要使用ClassPathResource 来得到bean 文件的资源对象  
           if (location.startsWith(CLASSPATH_URL_PREFIX)) {  
               return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());  
           }  
            try {  
                 // 如果是URL 方式,使用UrlResource 作为bean 文件的资源对象  
                URL url = new URL(location);  
                return new UrlResource(url);  
               }  
               catch (MalformedURLException ex) { 
               } 
               //如果既不是classpath标识,又不是URL标识的Resource定位,则调用  
               //容器本身的getResourceByPath方法获取Resource  
               return getResourceByPath(location);  
       }

    至此,完成了Resource的定位,获得Resource!

    XmlBeanDefinitionReader 加载Bean定义资源

    //XmlBeanDefinitionReader加载资源的入口方法  
       public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {  
           //将读入的XML资源进行特殊编码处理  
           return loadBeanDefinitions(new EncodedResource(resource));  
       } 
         //这里是载入XML形式Bean定义资源文件方法
       public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {    
       .......    
       try {    
            //将资源文件转为InputStream的IO流 
           InputStream inputStream = encodedResource.getResource().getInputStream();    
           try {    
              //从InputStream中得到XML的解析源    
               InputSource inputSource = new InputSource(inputStream);    
               if (encodedResource.getEncoding() != null) {    
                   inputSource.setEncoding(encodedResource.getEncoding());    
               }    
               //这里是具体的读取过程    
               return doLoadBeanDefinitions(inputSource, encodedResource.getResource());    
           }    
           finally {    
               //关闭从Resource中得到的IO流    
               inputStream.close();    
           }    
       }    
          .........    
    }    
       //从特定XML文件中实际载入Bean定义资源的方法 
       protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)    
           throws BeanDefinitionStoreException {    
       try {    
           int validationMode = getValidationModeForResource(resource);    
           //将XML文件转换为DOM对象,解析过程由documentLoader实现    
           Document doc = this.documentLoader.loadDocument(    
                   inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);    
           //这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则
           return registerBeanDefinitions(doc, resource);    
         }    
         .......    
         }

    1. XmlBeanDefinitionReader将Resource ——> IO流 ——>调用XML解析器完成XML解析得到 Document 对象,按照Spring的Bean规则解析过程由documentReader如下实现:

    即大体分为两步:

    • 按照XML解析得到Document对象
    • 按照Spring规则解析
     1 //按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构  
     2    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {  
     3        //得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析  
     4        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  
     5        //获得容器中注册的Bean数量  
     6        int countBefore = getRegistry().getBeanDefinitionCount();  
     7        //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口,//具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成  
     8        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));  //按照Spring规则解析
     9        //统计解析的Bean数量  
    10        return getRegistry().getBeanDefinitionCount() - countBefore;  
    11    }  
    12    //创建BeanDefinitionDocumentReader对象,解析Document对象  
    13    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {  
    14        return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));  
    15       }

    2. BeanDefinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReader对Bean定义的Document对象解析

    //根据Spring DTD对Bean的定义规则解析Bean定义Document对象  
        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  
            //获得XML描述符  
            this.readerContext = readerContext;  
            logger.debug("Loading bean definitions");  
            //获得Document的根元素  
            Element root = doc.getDocumentElement();  
            //具体的解析过程由BeanDefinitionParserDelegate实现,  
            //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素  
           BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);  
           //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性  
           preProcessXml(root);  
           //从Document的根元素开始进行Bean定义的Document对象  
           parseBeanDefinitions(root, delegate);
           //在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性  
           postProcessXml(root);  
       }  
       //创建BeanDefinitionParserDelegate,用于完成真正的解析过程  
       protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {  
           BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);  
           //BeanDefinitionParserDelegate初始化Document根元素  
           delegate.initDefaults(root);  
           return delegate;  
       }  
       //使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象  
       protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {  
           //Bean定义的Document对象使用了Spring默认的XML命名空间  
           if (delegate.isDefaultNamespace(root)) {  
               //获取Bean定义的Document对象根元素的所有子节点  
               NodeList nl = root.getChildNodes();  
               for (int i = 0; i < nl.getLength(); i++) {  
                   Node node = nl.item(i);  
                   //获得Document节点是XML元素节点  
                   if (node instanceof Element) {  
                       Element ele = (Element) node;  
                   //Bean定义的Document的元素节点使用的是Spring默认的XML命名空间  
                       if (delegate.isDefaultNamespace(ele)) {  
                           //使用Spring的Bean规则解析元素节点  
                           parseDefaultElement(ele, delegate);  
                       }  
                       else {  
                           //没有使用Spring默认的XML命名空间,则使用用户自定义的解析规则解析元素节点,这里也是解析AOP标签的入口
                           delegate.parseCustomElement(ele);  
                       }  
                   }  
               }  
           }  
           else {  
               //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的  
               //解析规则解析Document根节点  
               delegate.parseCustomElement(root);  
           }  
       }  
       //使用Spring的Bean规则解析Document元素节点  
       private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
           //如果元素节点是<Import>导入元素,进行导入解析  
           if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
               importBeanDefinitionResource(ele);  
           }  
           //如果元素节点是<Alias>别名元素,进行别名解析  
           else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
               processAliasRegistration(ele);  
           }  
           //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素,  
           //按照Spring的Bean规则解析元素  
           else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
               processBeanDefinition(ele, delegate);  
           }  
       }  
       //解析<Import>导入元素,从给定的导入路径加载Bean定义资源到Spring IoC容器中  
       protected void importBeanDefinitionResource(Element ele) {  
           //获取给定的导入元素的location属性  
           String location = ele.getAttribute(RESOURCE_ATTRIBUTE);  
           //如果导入元素的location属性值为空,则没有导入任何资源,直接返回  
           if (!StringUtils.hasText(location)) {  
               getReaderContext().error("Resource location must not be empty", ele);  
               return;  
           }  
           //使用系统变量值解析location属性值  
           location = SystemPropertyUtils.resolvePlaceholders(location);  
           Set<Resource> actualResources = new LinkedHashSet<Resource>(4);  
           //标识给定的导入元素的location是否是绝对路径  
           boolean absoluteLocation = false;  
           try {  
               absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();  
           }  
           catch (URISyntaxException ex) {  
               //给定的导入元素的location不是绝对路径  
           }  
           //给定的导入元素的location是绝对路径  
           if (absoluteLocation) {  
               try {  
                   //使用资源读入器加载给定路径的Bean定义资源  
                   int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);  
                   if (logger.isDebugEnabled()) {  
                       logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");  
                   }  
               }  
               catch (BeanDefinitionStoreException ex) {  
                   getReaderContext().error(  
                           "Failed to import bean definitions from URL location [" + location + "]", ele, ex);  
               }  
           }  
           else {  
               //给定的导入元素的location是相对路径  
               try {  
                   int importCount;  
                   //将给定导入元素的location封装为相对路径资源  
                   Resource relativeResource = getReaderContext().getResource().createRelative(location);  
                   //封装的相对路径资源存在  
                   if (relativeResource.exists()) {  
                       //使用资源读入器加载Bean定义资源  
                       importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);  
                       actualResources.add(relativeResource);  
                   }  
                   //封装的相对路径资源不存在  
                   else {  
                       //获取Spring IoC容器资源读入器的基本路径  
                       String baseLocation = getReaderContext().getResource().getURL().toString();  
                       //根据Spring IoC容器资源读入器的基本路径加载给定导入  
                       //路径的资源  
                       importCount = getReaderContext().getReader().loadBeanDefinitions(  
                               StringUtils.applyRelativePath(baseLocation, location), actualResources);  
                   }  
                   if (logger.isDebugEnabled()) {  
                       logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");  
                   }  
               }  
               catch (IOException ex) {  
                   getReaderContext().error("Failed to resolve current resource location", ele, ex);  
               }  
               catch (BeanDefinitionStoreException ex) {  
                   getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",  
                           ele, ex);  
               }  
           }  
           Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);  
           //在解析完<Import>元素之后,发送容器导入其他资源处理完成事件  
           getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));  
       }  
       //解析<Alias>别名元素,为Bean向Spring IoC容器注册别名  
       protected void processAliasRegistration(Element ele) {  
           //获取<Alias>别名元素中name的属性值  
           String name = ele.getAttribute(NAME_ATTRIBUTE);  
           //获取<Alias>别名元素中alias的属性值  
           String alias = ele.getAttribute(ALIAS_ATTRIBUTE);  
           boolean valid = true;  
           //<alias>别名元素的name属性值为空  
           if (!StringUtils.hasText(name)) {  
               getReaderContext().error("Name must not be empty", ele);  
               valid = false;  
           }  
           //<alias>别名元素的alias属性值为空  
           if (!StringUtils.hasText(alias)) {  
               getReaderContext().error("Alias must not be empty", ele);  
               valid = false;  
           }  
           if (valid) {  
               try {  
                   //向容器的资源读入器注册别名  
                   getReaderContext().getRegistry().registerAlias(name, alias);  
               }  
               catch (Exception ex) {  
                   getReaderContext().error("Failed to register alias '" + alias +  
                           "' for bean with name '" + name + "'", ele, ex);  
               }  
               //在解析完<Alias>元素之后,发送容器别名处理完成事件  
               getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));  
           }  
       }  
       //解析Bean定义资源Document对象的普通元素  
       protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
           // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类  
           //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现  
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //完成解析
    if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //向Spring IoC容器注册解析得到的Bean定义,这是Bean定义向IoC容器注册的入口 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  //完成注册 } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } //在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
    • 获取Document根元素root,并创建BeanDefinitionParserDelegate实现具体的解析根元素
    • 使用Spring默认的XML命名空间或者用户自定义,遍历根元素的所有子子节点,解析
    • 根据节点是(1)<Import>倒入元素(2)<Alias>别名元素(3)<Bean>元素 有不同的解析方式
    • processBeanDefinition() 解析得到的BeanDefinition外部使用Holder封装(beanDefinition, BeanName, aliasesArray),并向IOC容器注册

    3. parseBeanDefinitionElement()方法解析<Bean>元素

    //解析<Bean>元素的入口  
       public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {  
           return parseBeanDefinitionElement(ele, null);  
       }  
       //解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name  
       //和别名属性  
       public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
           //获取<Bean>元素中的id属性值  
           String id = ele.getAttribute(ID_ATTRIBUTE);  
           //获取<Bean>元素中的name属性值  
           String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);  
           ////获取<Bean>元素中的alias属性值  
           List<String> aliases = new ArrayList<String>();  
           //将<Bean>元素中的所有name属性值存放到别名中  
           if (StringUtils.hasLength(nameAttr)) {  
               String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);  
               aliases.addAll(Arrays.asList(nameArr));  
           }  
           String beanName = id;  
           //如果<Bean>元素中没有配置id属性时,将别名中的第一个值赋值给beanName  
           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");  
               }  
           }  
           //检查<Bean>元素所配置的id或者name的唯一性,containingBean标识<Bean>  
           //元素中是否包含子<Bean>元素  
           if (containingBean == null) {  
               //检查<Bean>元素所配置的id、name或者别名是否重复  
               checkNameUniqueness(beanName, aliases, ele);  
           }  
           //详细对<Bean>元素中配置的Bean定义的其他属性进行解析的地方  
           AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
           if (beanDefinition != null) {  
               if (!StringUtils.hasText(beanName)) {  
                   try {  
                       if (containingBean != null) {  
                           //如果<Bean>元素中没有配置id、别名或者name,且没有包含子//<Bean>元素,为解析的Bean生成一个唯一beanName并注册  
                           beanName = BeanDefinitionReaderUtils.generateBeanName(  
                                   beanDefinition, this.readerContext.getRegistry(), true);  
                       }  
                       else {  
                           //如果<Bean>元素中没有配置id、别名或者name,且包含了子//<Bean>元素,为解析的Bean使用别名向IoC容器注册  
                           beanName = this.readerContext.generateBeanName(beanDefinition);  
                           //为解析的Bean使用别名注册时,为了向后兼容                                    //Spring1.2/2.0,给别名添加类名后缀  
                           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);  
           }  
           //当解析出错时,返回null  
           return null;  
       }  
       //详细对<Bean>元素中配置的Bean定义其他属性进行解析,由于上面的方法中已经对//Bean的id、name和别名等属性进行了处理,该方法中主要处理除这三个以外的其他属性数据  
       public AbstractBeanDefinition parseBeanDefinitionElement(  
               Element ele, String beanName, BeanDefinition containingBean) {  
           //记录解析的<Bean>  
           this.parseState.push(new BeanEntry(beanName));  
           //这里只读取<Bean>元素中配置的class名字,然后载入到BeanDefinition中去  
           //只是记录配置的class名字,不做实例化,对象的实例化在依赖注入时完成  
           String className = null;  
           if (ele.hasAttribute(CLASS_ATTRIBUTE)) {  
               className = ele.getAttribute(CLASS_ATTRIBUTE).trim();  
           }  
           try {  
               String parent = null;  
               //如果<Bean>元素中配置了parent属性,则获取parent属性的值  
               if (ele.hasAttribute(PARENT_ATTRIBUTE)) {  
                   parent = ele.getAttribute(PARENT_ATTRIBUTE);  
               }  
               //根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition  
               //为载入Bean定义信息做准备  
               AbstractBeanDefinition bd = createBeanDefinition(className, parent);  
               //对当前的<Bean>元素中配置的一些属性进行解析和设置,如配置的单态(singleton)属性等  
               parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);  
               //为<Bean>元素解析的Bean设置description信息 
           bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    //对<Bean>元素的meta(元信息)属性解析 parseMetaElements(ele, bd); //对<Bean>元素的lookup-method属性解析 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //对<Bean>元素的replaced-method属性解析 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析<Bean>元素的构造方法设置 parseConstructorArgElements(ele, bd); //解析<Bean>元素的<property>设置 parsePropertyElements(ele, bd); //解析<Bean>元素的qualifier属性 parseQualifierElements(ele, bd); //为当前解析的Bean设置所需的资源和依赖对象 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(); } //解析<Bean>元素出错时,返回null return null; }

    具体解析:

    • 先解析id,name,别名属性
    • 对Bean其他属性解析得到AbstractBeanDefinition
    • 为解析的bean生成唯一的beanName并注册
    • 和beanName,别名数组一起封装为Holder并返回

    具体的“Bean其他属性”解析:

    • 根据Bean配置的class元素和parent属性创建BeanDefinition
    • 对<Bean>元素中配置的一些属性进行解析和设置,如配置单态属性
    • 解析Bean的description信息、meta信息、lookup-method属性、replace-method属性、构造方法设置、<property>设置
    • 为当前解析的Bean设置所需的资源和依赖的对象

    具体的“<property>”元素解析:

    <property name="car" value="200" ref="carBean"> 
        <value>奔驰E级</value>
        <array> </>
        <list> </>
      </property>
    //解析<Bean>元素中的<property>元素  
       public void parsePropertyElements(Element beanEle, BeanDefinition bd) {  
           //获取<Bean>元素中所有的子元素  
           NodeList nl = beanEle.getChildNodes();  
           for (int i = 0; i < nl.getLength(); i++) {  
               Node node = nl.item(i);  
               //如果子元素是<property>子元素,则调用解析<property>子元素方法解析  
               if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {  
                   parsePropertyElement((Element) node, bd);  
               }  
           }  
       }  
       //解析<property>元素  
       public void parsePropertyElement(Element ele, BeanDefinition bd) {  
           //获取<property>元素的名字   
           String propertyName = ele.getAttribute(NAME_ATTRIBUTE);  
           if (!StringUtils.hasLength(propertyName)) {  
               error("Tag 'property' must have a 'name' attribute", ele);  
               return;  
           }  
           this.parseState.push(new PropertyEntry(propertyName));  
           try {  
               //如果一个Bean中已经有同名的property存在,则不进行解析,直接返回。  
               //即如果在同一个Bean中配置同名的property,则只有第一个起作用  
               if (bd.getPropertyValues().contains(propertyName)) {  
                   error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  
                   return;  
               }  
               //解析获取property的值  
               Object val = parsePropertyValue(ele, bd, propertyName);  
               //根据property的名字和值创建property实例  
               PropertyValue pv = new PropertyValue(propertyName, val);  
               //解析<property>元素中的属性  
               parseMetaElements(ele, pv);  
               pv.setSource(extractSource(ele));  
               bd.getPropertyValues().addPropertyValue(pv);  
           }  
           finally {  
               this.parseState.pop();  
           }  
       }  
       //解析获取property值  
       public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {  
           String elementName = (propertyName != null) ?  
                           "<property> element for property '" + propertyName + "'" :  
                           "<constructor-arg> element";  
           //获取<property>的所有子元素,只能是其中一种类型:ref,value,list等  
           NodeList nl = ele.getChildNodes();  
           Element subElement = null;  
           for (int i = 0; i < nl.getLength(); i++) {  
               Node node = nl.item(i);  
               //子元素不是description和meta属性  
               if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&  
                       !nodeNameEquals(node, META_ELEMENT)) {  
                   if (subElement != null) {  
                       error(elementName + " must not contain more than one sub-element", ele);  
                   }  
                   else {//当前<property>元素包含有子元素  
                       subElement = (Element) node;  
                   }  
               }  
           }  
           //判断property的属性值是ref还是value,不允许既是ref又是value  
           boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);  
           boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);  
           if ((hasRefAttribute && hasValueAttribute) ||  
                   ((hasRefAttribute || hasValueAttribute) && subElement != null)) {  
               error(elementName +  
                       " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);  
           }  
           //如果属性是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象  
           //封装了ref信息  
           if (hasRefAttribute) {  
               String refName = ele.getAttribute(REF_ATTRIBUTE);  
               if (!StringUtils.hasText(refName)) {  
                   error(elementName + " contains empty 'ref' attribute", ele);  
               }  
               //一个指向运行时所依赖对象的引用  
               RuntimeBeanReference ref = new RuntimeBeanReference(refName);  
               //设置这个ref的数据对象是被当前的property对象所引用  
               ref.setSource(extractSource(ele));  
               return ref;  
           }  
            //如果属性是value,创建一个value的数据对象TypedStringValue,这个对象  
           //封装了value信息  
           else if (hasValueAttribute) {  
               //一个持有String类型值的对象  
               TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));  
               //设置这个value数据对象是被当前的property对象所引用  
               valueHolder.setSource(extractSource(ele));  
               return valueHolder;  
           }  
           //如果当前<property>元素还有子元素  
           else if (subElement != null) {  
               //解析<property>的子元素  
               return parsePropertySubElement(subElement, bd);  
           }  
           else {  
               //propery属性中既不是ref,也不是value属性,解析出错返回null        error(elementName + " must specify a ref or value", ele);  
               return null;  
           }  
        }

    a. ref被封装为指向依赖对象的一个引用

    b. value配置封装成一个字符串对象

    c. ref和value都通过“解析的数据类型属性值.setSource(extractSource(ele));”方法将属性值/引用与 所引用的属性 关联起来

    如果存在子元素则继续解析子元素:

    //解析<property>元素中ref,value或者集合等子元素  
       public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {  
           //如果<property>没有使用Spring默认的命名空间,则使用用户自定义的规则解析//内嵌元素  
           if (!isDefaultNamespace(ele)) {  
               return parseNestedCustomElement(ele, bd);  
           }  
           //如果子元素是bean,则使用解析<Bean>元素的方法解析  
           else if (nodeNameEquals(ele, BEAN_ELEMENT)) {  
               BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);  
               if (nestedBd != null) {  
                   nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);  
               }  
               return nestedBd;  
           }  
           //如果子元素是ref,ref中只能有以下3个属性:bean、local、parent  
           else if (nodeNameEquals(ele, REF_ELEMENT)) {  
               //获取<property>元素中的bean属性值,引用其他解析的Bean的名称  
               //可以不再同一个Spring配置文件中,具体请参考Spring对ref的配置规则  
               String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);  
               boolean toParent = false;  
               if (!StringUtils.hasLength(refName)) {  
                    //获取<property>元素中的local属性值,引用同一个Xml文件中配置  
                    //的Bean的id,local和ref不同,local只能引用同一个配置文件中的Bean  
                   refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);  
                   if (!StringUtils.hasLength(refName)) {  
                       //获取<property>元素中parent属性值,引用父级容器中的Bean  
                       refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);  
                       toParent = true;  
                       if (!StringUtils.hasLength(refName)) {  
                           error("'bean', 'local' or 'parent' is required for <ref> element", ele);  
                           return null;  
                       }  
                   }  
               }  
               //没有配置ref的目标属性值  
               if (!StringUtils.hasText(refName)) {  
                   error("<ref> element contains empty target attribute", ele);  
                   return null;  
               }  
               //创建ref类型数据,指向被引用的对象  
               RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);  
               //设置引用类型值是被当前子元素所引用  
               ref.setSource(extractSource(ele));  
               return ref;  
           }  
           //如果子元素是<idref>,使用解析ref元素的方法解析  
           else if (nodeNameEquals(ele, IDREF_ELEMENT)) {  
               return parseIdRefElement(ele);  
           }  
           //如果子元素是<value>,使用解析value元素的方法解析  
           else if (nodeNameEquals(ele, VALUE_ELEMENT)) {  
               return parseValueElement(ele, defaultValueType);  
           }  
           //如果子元素是null,为<property>设置一个封装null值的字符串数据  
           else if (nodeNameEquals(ele, NULL_ELEMENT)) {  
               TypedStringValue nullHolder = new TypedStringValue(null);  
               nullHolder.setSource(extractSource(ele));  
               return nullHolder;  
           }  
           //如果子元素是<array>,使用解析array集合子元素的方法解析  
           else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {  
               return parseArrayElement(ele, bd);  
           }  
           //如果子元素是<list>,使用解析list集合子元素的方法解析  
           else if (nodeNameEquals(ele, LIST_ELEMENT)) {  
               return parseListElement(ele, bd);  
           }  
           //如果子元素是<set>,使用解析set集合子元素的方法解析  
           else if (nodeNameEquals(ele, SET_ELEMENT)) {  
               return parseSetElement(ele, bd);  
           }  
           //如果子元素是<map>,使用解析map集合子元素的方法解析  
           else if (nodeNameEquals(ele, MAP_ELEMENT)) {  
               return parseMapElement(ele, bd);  
           }  
           //如果子元素是<props>,使用解析props集合子元素的方法解析  
           else if (nodeNameEquals(ele, PROPS_ELEMENT)) {  
               return parsePropsElement(ele);  
           }  
           //既不是ref,又不是value,也不是集合,则子元素配置错误,返回null  
           else {  
               error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);  
               return null;  
           }  
        }

    对<property>元素配置的Array、List、Set、Map、Prop等各种集合元素解析生成对应的数据对象,比如ManagedList、ManagedArray、ManagedSet等,这些Managed类是Spring对象BeanDefiniton的数据封装。

    至此,IOC容器完成了载入和解析,将定义的资源文件转化为BeanDefinition!

    解析过后的BeanDefinition在IoC容器中的注册:

    调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean:

    //将解析的BeanDefinitionHold注册到容器中 
    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  
        throws BeanDefinitionStoreException {  
            //获取解析的BeanDefinition的名称
             String beanName = definitionHolder.getBeanName();  
            //向IoC容器注册BeanDefinition 
            registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());  
            //如果解析的BeanDefinition有别名,向容器为其注册别名  
             String[] aliases = definitionHolder.getAliases();  
            if (aliases != null) {  
                for (String aliase : aliases) {  
                    registry.registerAlias(beanName, aliase);  
                }  
            }  
    }

    真正完成注册功能的是DefaultListableBeanFactory,使用一个HashMap的集合对象存放IoC容器中注册解析的BeanDefinition:

    //存储注册的俄BeanDefinition  
       private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();  
       //向IoC容器注册解析的BeanDefiniton  
       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");  
           //校验解析的BeanDefiniton  
           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);  
               //检查是否有同名的BeanDefinition已经在IoC容器中注册,如果已经注册,  
               //并且不允许覆盖已注册的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 {//如果允许覆盖,则同名的Bean,后注册的覆盖先注册的  
                       if (this.logger.isInfoEnabled()) {  
                           this.logger.info("Overriding bean definition for bean '" + beanName +  
                                   "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");  
                       }  
                   }  
               }  
               //IoC容器中没有已经注册同名的Bean,按正常注册流程注册  
               else {  
                   this.beanDefinitionNames.add(beanName);  
                   this.frozenBeanDefinitionNames = null;  
               }  
               this.beanDefinitionMap.put(beanName, beanDefinition);  
               //重置所有已经注册过的BeanDefinition的缓存  
               resetBeanDefinition(beanName);  
           }  
        }

    完成了BeanDefinition注册!

    现在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。

    流程分析

    Spring容器初始化大模块
    1.BeanDefinition的Resource定位
    2.BeanDefinition的载入
    3.BeanDefinition的注册,注册到一个Map<String/*beanName*/,BeanDefinition>


    1.Resource定位
      根据路径获取Resource对象,url,类路径,path("/"开头)三种处理

    2.载入BeanDefinition(BeanDefinitionReader#loadBeanDefinitions)
      xml/Goovy/properties三种实现
      1. 将Resource转为IO流,有一层封装InputSource
      2. IO流转为Document对象,准备解析Document(Document元素节点有Spring默认的三个<import>/<alias>/<bean>,也有自定义的,会有不同的处理)
        2.1 <import>从指定location导入资源到IOC容器
        2.2 <alias>将Bean的别名注册到IOC容器
        2.3 <bean>解析bean
          2.3.1 beanName赋值,默认是id,否则是第一个别名,都没有会生成一个唯一BeanName。会检查id,beanName和别名是否重复
          2.3.2 根据bean标签的class属性和parent属性创建新的BeanDefinition
          2.3.3 向BeanDefinition赋值,关于这个bean的基本信息例如单例,源信息描述等等,其中重要是<property>。property子标签可以有多个但是重名的只解析第一个
            2.3.3.1 property类型是ref和value或集合三种之一。不同类型生成不同对象。
            2.3.3.2 ref类型根据引用的对象名封装成RuntimeBeanReference(refName)
            2.3.3.3 value类型封装成TypedStringValue(value),value现在是字符串后面会判断具体类型
            2.3.3.4 还有子标签说明是集合,继续解析子标签

    3.将BeanDefinition注册到IOC容器中
      放入Map<String,BeanDefinition>中,如果不允许重名,则抛出异常,否则覆盖原有的。注册过程需要同步

    人生就像蒲公英,看似自由,其实身不由己。
  • 相关阅读:
    UVA 408 (13.07.28)
    linux概念之用户,组及权限
    Java实现 蓝桥杯 历届试题 网络寻路
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 九宫重排
    Java实现 蓝桥杯 历届试题 九宫重排
  • 原文地址:https://www.cnblogs.com/walker993/p/9457878.html
Copyright © 2011-2022 走看看