spring容器和装配Bean:

 

  • 以FileSystemXmlApplicationContext为例说明IoC容器初始过程
  • FileSystemXmlApplicationContext构造方法中refresh()是IoC容器启动的入口
  • 启动过程将包含三大步骤
    • Resource定位
    • BenDefinition载入和解析
    • BeanDefinition在IoC中注册

Resource资源定位

  • 由ResourceLoader通过Resource接口定位资源,Resouce接口有如下实现,通过名字就能猜到大概都能通过哪些方式定位资源

     

    图片.png

  • FileSystemXmlApplicationContext通过继承DefaultResourceLoader具备了定位Resouce功能,下面这张继承关系图非常重要

     

    图片.png

  • DefaultResourceLoader实现了ResourceLoader接口

     

    图片.png

  • refresh()载入了BeanDefiniation,会在载入章节详细说明

     

    图片.png

  • 应用于文件系统的Resource实现,在BeanDefiniationReader.loadBeanDefination()中被调用loadBeanDefination()采用了模板方法,具体Resource定位方式由子类决定,在org.springframework.core.io.DefaultResourceLoader中被调用

     

    图片.png

  • 创建DefaultListableBeanFactory和加载配置文件在org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()完成

     

    图片.png

  • 分析一下是如何调用到AbstractRefreshableApplicationContext.refreshBeanFactory()呢,FileSystemXmlApplicationContext在构造中调用了refresh(),refresh()在org.springframework.context.support.AbstractApplicationContext被调用

     

    图片.png

  • refresh()中有一个重要的方法obtainFreshBeanFactory(),调用到org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()

     

    图片.png

  • 在回到org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()中(回看前面的FileSystemXmlApplicationContext结成结构,对于下面的调用理解很重要),createBeanFactory()创建了DefaultListableBeanFactory,这是一个默认的IoC实现

     

    图片.png

  • org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory)中装载BeanDefination

     

    图片.png

  • 具体的解析过程在org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String, Set<Resource>)定义

    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }
                //对Resource路径进行解析,如Ant风格路径
        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                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 {
            // Can only load single resources by absolute URL.
            Resource resource = resourceLoader.getResource(location);
            int loadCount = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }
            return loadCount;
        }
    }

BenDefinition载入和解析

  • BenDefinition是IoC容器中保存Bean信息的一种数据结构,IoC容器对Bean的管理和注入其本质上都是对BeanDefiniation的操作
  • 在FileSystemXmlApplicationContext构造方法中调用了父类的refresh(),这个方法执行过程就是整个Bean的生命周期
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // 在子类中调用refreshBeanFactory()
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                //设置BeanFacotry后置处理
                postProcessBeanFactory(beanFactory);

                //调用BeanFactory后置处理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册Bean后置处理器,在Bean创建过程中调用
                registerBeanPostProcessors(beanFactory);

                // 初始化上小文消息
                initMessageSource();

                // 初始化上下文事件
                initApplicationEventMulticaster();

                // 初始化特殊bean
                onRefresh();

                // 注册Bean监听器
                registerListeners();

                // 实例化单例bean
                finishBeanFactoryInitialization(beanFactory);

                // 结束容器初始化,发布容器事件
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // 销毁已经创建的单例bean
                destroyBeans();

                // 重置标志位
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }
  • 上节中已经看到过是如何加载BeanDefiniation了,FileSystemXmlApplicationContext默认使用的IoC容器是DefaultListableBeanFactory

     

    图片.png

  • 配置文件读取在org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource, Resource)中,registerBeanDefinitions()对BeanDefinitation解析过程,也就是Spring配置文件中配置Bean的规则

     

    图片.png

  • BeanDefiniation载入过程分为两部分,首先创建XML的解析器document,在按照Spring配置文件规则解析,具体的解析过程在org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document, XmlReaderContext)中,

     

    图片.png

  • org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element, BeanDefinitionParserDelegate)中想IoC容器注册BeanDefiniation,BeanDefinitionHolder封装了BeanDefiniation,增加了bean的名字和别名,bean的解析在BeanDefinitionParserDelegate完成,解析过程十分繁琐,参考Spring配置文件的配置规则

     

    图片.png

BeanDefinition在IoC中注册

  • 经过Resource定位,和BeanDefiniation的载入和解析,BeanDefiniation已经在IoC容器中了,但还不能使用,需要向IoC容器注册,在DefaultListableBeanFactory中通过一个Map维护这些BeanDefiniation

     

    图片.png

  • 注册过程在org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String, BeanDefinition)中
    @Override
    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;

        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
                //如果出现beanName相同的情况,抛异常
        if (oldBeanDefinition != null) {
            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 (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

  • 在org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String, BeanDefinition)中填充beanDefinitionMap,现在DefaultListableBeanFactory已经建立完整的Bean的配置信息,IoC以后要做的事就是对这些beanDefinitionMap中的数据进行检索和使用,这些数据也是IoC容器依赖注入的基础


spring容器和装配Bean:
  1、容器是spring的核心,使IoC管理所有和组件
  2、spring的两种容器:a、BeanFactoy
                       b、ApplicationContext应用上下文
  3、BeanFactory:BeanhFactory使用延迟加载所有的Bean,为了从BeanhFactory得到一个Bean,只要调用

                  getBean()方法,就能获得Bean
  4、ApplicationContext:a、提供文本信息解析,支持I18N
                         b、提供载入文件资源的通用方法
                         c、向注册为监听器的Bean发送事件
                         d、ApplicationContext接口扩展BeanFactory接口
                         e、ApplicationContext提供附加功能
  5、ApplicationContext的三个实现类:a、ClassPathXmlApplication:把上下文文件当成类路径资源
                                     b、FileSystemXmlApplication:从文件系统中的XML文件载入上

                                        下文定义信息
                                     c、XmlWebApplicationContext:从Web系统中的XML文件载入上下

                                        文定义信息
  6、在默认情况下,Bean全都是单态,在<bean>中的singleton为false
  7、<bean>中的id属性必须遵循Java规范,而name属性可以不遵循
  8、Bean的实例化的时候需要一些初始化的动作,同样当不再使用的时候,需要从容器中将其销毁
  9、对象的初始化:<bean init-method="方法名">
  10、对象的销毁:<bean destroy-method="方法名">
      销毁对象的过程:a、主线程先被中断
                      b、Java虚拟机使用垃圾回收机制回收Bean对象
  11、Bean设置:设值注入:1)简单配置:<bean id="xxx" class="Bean的全称类名">
                                         <property name="xx" value="xxxxx"></property>
                                       </bean>
                                      value中的值可以是基本数据类型或者String类型,spring将会

                                      自动判断设置的类型并且
                                      将其转换成合适的值
                          2)引用配置:<bean id="xxx" class="Bean的全称类名">
                                         <property name="xx" ref="xxxxx"></property>
                                      </bean>
                                      ref中的值是引用数据类型,spring容器会完成获取工作
                          3)List和数组:<bean id="xxx" class="Bean的全称类名">
                                           <property name="list">
                                               <list>
                                                <value></value>
                                                <ref bean=""/>
                                               </list>
                                           </property>
                                        </bean>
                                        list元素内可以是任何元素,但不能违背Bean所需要的对象类

                                        型
                          4)Set配置:和<list>一样,将<list>改成<set>
                          5)Map配置:Map中的每条数据是由一个键和一个值组成,用<entry>元素来定

                                      义
                                     <bean id="xxx" class="Bean的全称类名">
                                           <property name="list">
                                              <entry key="key1">
                                                  <value></value>
                                              </entry>
                                           </property>
                                        </bean>
                                     <bean id="xxx" class="Bean的全称类名">
                                           <property name="list">
                                              <entry key="key1">
                                                  <ref bean=""/>
                                              </entry>
                                           </property>
                                        </bean>
                                注意:配置entry时,属性key的值只能是String,因为Map通常用

                                      String作为主键
                          6)Properties配置:使用<props>和<map>相似,最大区别是<prop>的值都是

                                             String
                  注意:使用设值注入必须要有set方法,通过name属性找set方法

                  优势:a、通过set()方法设定更直观,更自然

                        b、当依赖关系较复杂时,使用set()方法更清晰
                构造子注入:必须要有无参和带参的构造方法,加上index(值从0开始)属性避免注入混

                            淆

                           <constractor-arg>

               注意:设值注入可以和构造子注入混合使用。先调用构造方法产生对象,再调用set()方法

                     赋值。但只使用设值注入时,会先调用无参的构造方法

               优势:a、依赖关系一次性设定,对外不准修改

                     b、无需关心方式

                     c、注入有先后顺序,防止注入失败
                               

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值