zoukankan      html  css  js  c++  java
  • Spring <bean> 之间的关系&整合多个配置文件

    Spring 不但可以通过 <ref>  引用另一个 Bean,建立起 Bean 和 Bean 之间的依赖关系,<bean> 元素标签之间也可以建立类似的关系,完成一些特殊的功能。

    1.继承

    OOP思想告诉我们,如果多个类拥有相同的方法和属性,则可以引入一个父类,在父类中定义这些类共同的方法和属性,以消除重复的代码。同样,如果多个 <bean> 存在相同的配置信息,则 Spring 允许定义一个父<bean>,子<bean>将自动继承父<bean>的配置信息。

    下面通过一个实例,对使用和未使用父子<bean>的配置进行比较,从中看出父子<bean>给配置带来的便利性,如下所示。

    未使用父子<bean>的配置

    <bean id="car1" class="com.smart.tagdepend.Car"
        p:brand="红旗CA72" p:price="2000.00" p:color="黑色" />
    <bean id="car2" class="com.smart.tagdepend.Car"
        p:brand="红旗CA72" p:price="2000.00" p:color="红色" />

    上面代码配置了两个 car Bean,我们发现这两个 Bean 的配置存在大量的重复信息。事实上,二者除了 color 属性配置值不一样外,其他配置信息都相同。通过父子<bean>的继承关系就可以很好地消除这种重复的配置信息如下所示。

    使用父子<bean>的配置

    <!-- ①定义为抽象<bean> -->
    <bean id="abstractCar" class="com.smart.tagdepend.Car"
      p:brand="红旗CA72" p:price="2000.00" p:color="黑色" abstract="true"/>
    <!-- ②继承于abstractCar -->          
    <bean id="car3" parent="abstractCar">
      <property name="color" value="红色"/>
    </bean>
    <!-- ③继承于abstractCar -->    
    <bean id="car4" parent="abstractCar" >
      <property name="color" value="白色"/>
    </bean>    

    car3 和 car4 这两个 <bean> 都继承于 abstractCar 的 <bean>,Spring 会将父<bean>的配置信息传递给子<bean>。如果子<bean>提供了父<bean>已有的配置信息,那么子<bean>的配置信息将覆盖父<bean>的配置信息。

    父<bean>的主要功能是简化子<bean>的配置,所以一般声明为 abstract="true",表示这个<bean>不实例化为一个对应的Bean。如果用户没有指定 abstract="true",则 Spring IOC容器会实例化一个名为 abstractCar 的 Bean。

    2.依赖
    一般情况下,可以使用 <ref> 元素标签建立对其他 Bean 的依赖关系,Spring 负责管理这些 Bean 的关系。当实例化一个 Bean 时,Spring 保证该 Bean 所依赖的其他 Bean 已经初始化。

    但在某些情况下,这种 Bean 之间的依赖关系并不那么明显。下面举一个例子。“小春论坛”拥有很多系统参数(如会话过期时间、缓存更新时间等),这些系统参数用于控制系统的运行逻辑。我们用一个 SystemSettings 类表示这些系统参数。

    public class SystemSettings {
       public static int SESSION_TIMEOUT = 30;
       public static int REFRESH_CYCLE = 60;
    }

    在 SystemSettings 类中为每个系统参数提供了默认值,但一个灵活的论坛必须提供一个管理后台,在管理后台中可以调整这些系统参数并保存到后台数据库中,在系统启动时,初始化程序从数据库后台加载这些系统参数的配置值以覆盖默认值。

    public class SysInit {
       public SysInit(){  
           System.out.println("SysInit");
           //模拟从数据库中加载系统设置信息
           SystemSettings.REFRESH_CYCLE = 100;
           SystemSettings.SESSION_TIMEOUT = 10;
       }
    }

    假设论坛有一个缓存刷新管理器,它需要根据系统参数 SystemSettings.REFRESH  CYCLE创建缓存刷新定时任务。

    public class CacheManager {
       public CacheManager(){
           Timer timer = new Timer();
           TimerTask cacheTask = new CacheTask();
           timer.schedule(cacheTask,0,SystemSettings.REFRESH_CYCLE*1000);  
       }
    }

    在以上实例中,CacheManager 依赖于 SystemSettings,而 SystemSettings 的值由 Syslnit 负责初始化。虽然 CacheManager 不直接依赖于 Syslnit,但从逻辑上看,CacheManager 希望在 Syslnit 加载并完成系统参数设置后再启动,以避免调用不到真实的系统参数值。如果这3个 Bean 都在 Spring 配置文件中定义,那么如何保证 Syslnit 在 CacheManager 之前进行初始化呢?

    Spring 允许用户通过 depends-on 属性显式指定 Bean 前置依赖的 Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好。

    <!-- <bean>的依赖 -->
    <bean id="cacheManager" class="com.smart.tagdepend.CacheManager" depends-on="sysInit" />
    <bean id="sysInit" class="com.smart.tagdepend.SysInit" />

    通过 depends-on 属性将 syslnit 指定为 manager 前置依赖的 Bean,这样就可以保证 managerBean 在实例化并运行时所引用的系统参数是最新的设置值,而非 SystemSettings 类中的默认值。如果前置依赖于多个 Bean,则可以通过逗号、空格或分号的方式创建 Bean 的名称。

    3.引用

    假设一个<bean>要引用另一个<bean>的id属性值,则可以直接使用以下配置方式:

    <!-- <bean>引用 -->
    <bean id="car" class="com.smart.tagdepend.Car"/> ①
    <bean id="boss" class="com.smart.tagdepend.Boss" >  ②
      <property name="carId"  >
        <value>car</value>
      </property>
    </bean>

    假设希望将 boss Bean 的 carld 设置为①处 <bean> 的 id 值,虽然可以通过②处的方式以字面值的形式进行设置,但二者之间并没有建立引用关系。一般情况下,在一个 Bean 中引用另一个 Bean 的 id 是希望在运行期通过 getBean(beanName) 方法获取对应的 Bean。由于 Spring 并不会在容器启动时对属性配置值进行特殊检查,因此,即使编写错误,也需要等到具体调用时才会发现。

    Spring 为此提供了一个 <idref> 元素标签,可以通过 <idref> 引用另一个 <bean> 的名字。在容器启动时,Spring 负责检查引用关系的正确性,这样就可以提前发现错误。因此,下面的配置是推荐的优化方案:

    <bean id="car" class="com.smart.tagdepend.Car"/><bean id="boss" class="com.smart.tagdepend.Boss" >  ②
        <idref bean="car"/>
      </property>
    </bean>

    假设②处由于配置错误,误将 <idref bean="car"/> 写为 <idref bean="cat"/>,那么 Spring 容器在启动时,将会抛出 BeanDefinitionStoreException,提示容器中没有名为 cat 的 Bean

    如果引用者和被引用者的 <bean> 位于同一个XML配置文件中,则可以使用 <idref local="car"> 的配置方式,这时IDE的XML分析器就可以在开发期发现引用错误了。

    整合多个配置文件

    对于一个大型应用来说,可能存在多个 XML 配置文件,在启动 Spring 容器时,可以通过一个 String 数组指定这些配置文件。Spring 还允许通过 <import> 将多个配置文件引入到一个文件中,进行配置文件的集成。这样,在启动 Spring 容器时,仅需指定这个合并好的配置文件即可。

    <import resource="classpath:com/smart/impt/beans1.xml"/> ①
    <bean id="boss1" class="com.smart.fb.Boss" p:name="John" p:car-ref="car1"/>
    <bean id="boss2" class="com.smart.fb.Boss" p:name="John" p:car-ref="car2"/>

    假设已经在 beans1.xml 中配置了 car1 和 car2 的 Bean,在①处通过 <import> 的 resource 属性引入 beans1.xml,beans2.xml 就拥有了完整的配置信息,Spring 容器仅需通过 beans2.xml 就可以加载所有的配置信息。

    需要指出的是,如果一个配置文件 a.xml 定义的 <bean> 引用了另一个配置文件 b.xml 定义的 <bean>,那么并不一定需要通过 <import> 引入 b.xml,只需在启动 Spring 容器时,a.xml 和 b.xml 都在配置文件列表中即可。区别在于,如果 a.xml 采用 import 引入了 b.xml,相当于 a.xml 一个文件就包含了 a.xml 和 b.xml 两个文件的内容,因此 Spring 容器启动时仅需加载 a.xml 即可:否则就需要在启动 Spring 容器时,同时加载 a.xml 和 b.xml 配置文件,以便在内存中对 a.xml 和 b.xml 进行合并。

    一个 XML 配置文件可以通过 <import> 组合多个外部的配置文件,resource 属性支持 Spring 标准的资源路径。

  • 相关阅读:
    mvc
    拦截器
    使用HttpWebRequest和HtmlAgilityPack抓取网页(拒绝乱码,拒绝正则表达式)
    编译和解释的区别是什么?
    15 个最佳的 jQuery 表格插件
    编程小白必备——主流语言C语言知识点
    妹子找你修电脑,按照这几步操作,你就是黑客大佬!
    网络管理监视很重要!学编程的你知道哪些不错的网络监控工具?2020 最好的Linux网络监控工具分享给你
    为什么程序员要跳槽,钱并非第一位
    代码编写行为准则,编码是一个认真思考的过程,如何有效提高代码的可读性?
  • 原文地址:https://www.cnblogs.com/jwen1994/p/11062209.html
Copyright © 2011-2022 走看看