概述

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

在Spring容器中,两个Bean之间 除了注入关系外,还存在 继承、依赖、引用 三种关系:

  • 继承关系:在Spring容器当中允许使用abstract标签来定义一个父bean,parent标签来定义一个子bean。子bean将自动继承父bean的配置信息。

  • 依赖关系:Spring允许用户通过depends-on标签来设定bean的前置依赖bean,前置依赖的bean会在本bean实例化之前创建好,供本bean使用。

  • 引用关系:不光可以通过ref标签来引用其他的bean,而且可以通过idref标签来引用其他bean的名字。它的主要作用是:在Spring容器启动的时候就可以检查引用关系的正确性,从而可以提前发现配置信息是否存在错误。


继承

如果多个bean存在相同的配置信息,Spring允许定义一个父Bean,子bean将自动继承父bean的配置信息。

Spring会将父bean的配置信息传递个子bean,如果子bean提供了父bean已有的配置信息,那么子bean的配置信息将覆盖父bean的配置信息。

父bean的功能主要是简化子bean的配置,所以一般声明为 abstract=”true”, 标识这个bean不会被实例化为一个对应的bean。

实例

Spring-bean之间的关系_Spring学习

POJO

package com.xgj.ioc.beansRelation.extend;

public class Plane {

    private String brand;
    private String color;
    private int speed;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public void introduce() {
        System.out.println("brand:" + brand + ",speed:" + speed + ",color:"
                + color);
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"   
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
    <bean id="planeOne" class="com.xgj.ioc.beansRelation.extend.Plane"
            p:brand="F35" p:speed="1200" p:color="white"/>



    <bean id="planeTwo" class="com.xgj.ioc.beansRelation.extend.Plane"
            p:brand="F35" p:speed="1200" p:color="blue"/>

     -->

     <bean id="abstractPlane" class="com.xgj.ioc.beansRelation.extend.Plane" abstract="true"
        p:brand="F35" p:speed="1200" p:color="default"/>

     <bean id="planeOne" parent="abstractPlane" 
        p:color="white"/>

     <bean id="planeTwo" parent="abstractPlane" 
        p:color="blue"/>

</beans>

测试类

package com.xgj.ioc.beansRelation.extend;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeansExtendTest {

    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/ioc/beansRelation/extend/beans.xml");

        ctx.getBean("planeOne", Plane.class).introduce();
        ctx.getBean("planeTwo", Plane.class).introduce();
    }

}

运行结果

Spring-bean之间的关系_Spring学习_02

可以看到这两个bean都继承自abstractPlane这个父bean,在上面的代码中子bean就只改变了color属性,其他属性都跟父类相同。


依赖

在Spring容器中,当使用depends-on标签建立对其他Bean的依赖关系时,Spring容器负责管理这些Bean的关系,当实例化一个Bean时,容器保证该Bean所依赖的Bean已经初始化;如果前置依赖多个Bean,可以通过逗号或空格方式配置Bean名称。

实例

Spring-bean之间的关系_Spring教程_03

举个例子:

在某论坛系统当中,具有很多的启动参数,比如:会话过期时间、缓存更新时间等。这些启动参数用来控制系统的运行逻辑,我们使用一个SystemSetting类来表示这些参数。

package com.xgj.ioc.beansRelation.depend;

public class SystemSetting {

    public static int SESSION_TIMEOUT = 30;
    public static int REFRESH_CYCLE = 60;

}

在这里我们定义了两个系统参数,我们这里直接定义了这两个参数的值,但在真正的论坛系统当中这些值应该是可以动态设置的,并及时保存到后台数据库当中。在系统启动时,初始化程序来从后台数据库获取这些系统参数的配置值以覆盖默认的值。 在这里我们模拟从数据库中加载系统值。

package com.xgj.ioc.beansRelation.depend;

public class SysInit {

    public SysInit() {
        SystemSetting.SESSION_TIMEOUT = 10;
        SystemSetting.REFRESH_CYCLE = 100;
    }

}

假设我们的系统需要一个缓存刷新管理器,他需要根据SystemSettings.REFRESH_CYCLE 的值来创建缓存定时刷新任务,那么请看如下 的代码:

package com.xgj.ioc.beansRelation.depend;

import java.util.Timer;
import java.util.TimerTask;

public class CacheManager {

    public CacheManager() {
        Timer timer = new Timer();
        TimerTask cacheTask = new CacheTask();

        System.out.println("SystemSetting.REFRESH_CYCLE:"
                + SystemSetting.REFRESH_CYCLE);

        timer.schedule(cacheTask, 0, SystemSetting.REFRESH_CYCLE);
    }

}
package com.xgj.ioc.beansRelation.depend;

import java.util.TimerTask;

public class CacheTask extends TimerTask {

    @Override
    public void run() {
        try {
            // bussiness logic
            System.out.println("bussiness run");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

从上面的代码中可以看出 CacheManager依赖与SystemSetting,而SystemSetting又依赖与SysInit。 可以看到SysInit必须首先执行然后才能执行接下来的代码。 如果这三个bean都在Spring当中定义,那么我们该如何保证SysInit bean被首先执行呢? 那么就得使用depends-on属性标签了

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="cacheManager" class="com.xgj.ioc.beansRelation.depend.CacheManager"
        depends-on="sysInit"/>

    <bean id="sysInit" class="com.xgj.ioc.beansRelation.depend.SysInit"/>
</beans>

测试类

package com.xgj.ioc.beansRelation.depend;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeansDependTest {

    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/ioc/beansRelation/depend/beans.xml");

    }
}

运行结果
Spring-bean之间的关系_Spring教程_04


引用

在Spring容器中,当使用<ref>标签引用另外一个Bean时,但实际上两者并没有建立引用关系,即使我们编写错误,也需要在运行期才可以发现。 因此Spring提供了<idref>元素标签,通过<idref>引用另一个Bean的名字,可以在容器启动的时候,检查引用关系的正确性,这样可以提前发现错误的配置信息

实例

Spring-bean之间的关系_Spring学习_05

POJO

package com.xgj.ioc.beansRelation.reference;

public class Pilot {

    private String planeId;

    public String getPlaneId() {
        return planeId;
    }

    public void setPlaneId(String planeId) {
        this.planeId = planeId;
    }

    @Override
    public String toString() {
        System.out.println("*********" + getPlaneId());
        return "planeId:" + getPlaneId();
    }
}

POJO

package com.xgj.ioc.beansRelation.reference;

public class Plane {

}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"   
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- <bean>引用 -->
    <bean id="pilot" class="com.xgj.ioc.beansRelation.reference.Pilot" >
       <property name="planeId" >
          <idref bean="plane"/>
       </property>
    </bean>

    <bean id="plane" class="com.xgj.ioc.beansRelation.reference.Plane"/>

</beans>

测试类

package com.xgj.ioc.beansRelation.reference;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeansRefTest {

    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/ioc/beansRelation/reference/beans.xml");

        Pilot pilot = ctx.getBean("pilot", Pilot.class);
        pilot.setPlaneId("99");
        pilot.toString();
    }
}

运行结果

Spring-bean之间的关系_Spring教程_06


总结

Spring为bean提供了一系列的关系:注入、继承、依赖、引用 使用bean之间的关系可以将代码中繁琐的类间关系转移到配置文件当中来,降低了代码的耦合性,也方便系统的模块化管理。