上一篇中简单了说了一下使用XML进行bean的配置以及bean的两种注入方式:属性注入,即set方法注入;构造方法注入,即通过指定与构造方法一致的参数个数与类型。在构造方法注入中,可以使用index指定参数位置,index是0从开始的,还可以使用type属性指定参数类型,通过这二者组合,IoC容器就可以明确的知道使用哪个构造方法进行依赖注入。


如何引用其他的bean?


 引用其他的bean的方法一般来说有两种:一是通过ref属性或者标签,为bean的属性或者构造参数指定要引用的bean,;二是在使用内部bean,即在属性或者构造方法里面包含bean的声明。


使用ref标签或者属性引用其他bean

  我们结合上一篇的代码,新建一个Person类,Person有一个Car,代码如下,Person类有三个属性:name,age以及car,car是Car类型的:

package com.study.spring;

public class Person {
	private String name;
	private int age;
	private Car car;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Car getCar() {
		return car;
	}
	public void setCar(Car car) {
		this.car = car;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
	}
	public Person() {
		super();
	}
	public Person(String name, int age, Car car) {
		super();
		this.name = name;
		this.age = age;
		this.car = car;
	}
}

  接下来让我们看看如何去配置一个Person类型的bean,下面是配置文件:



<bean id="car2" class="com.study.spring.Car"> <constructor-arg value="Audi" type="java.lang.String"></constructor-arg> <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg> <constructor-arg value="240" type="int"></constructor-arg> </bean> <bean id="person" class="com.study.spring.Person"> <property name="name" value="Aces"></property> <property name="age" value="18"></property> <!-- 可以使用property的ref属性,建立bean之间的引用关系 --> <property name="car" ref="car2"></property> </bean> <bean id="person2" class="com.study.spring.Person"> <property name="name" value="Aces"></property> <property name="age" value="18"></property> <!-- 可以使用property的子节点ref标签,建立bean之间的引用关系 --> <property name="car"> <ref bean="car2" /> </property> </bean> <bean id="person3" class="com.study.spring.Person"> <property name="name" value="Aces"></property> <property name="age" value="18"></property> <!-- 内部bean,不能被外部使用,只能在内部使用 --> <property name="car"> <bean class="com.study.spring.Car"> <constructor-arg value="Ford" type="java.lang.String"></constructor-arg> <constructor-arg value="Changan" type="java.lang.String"></constructor-arg> <constructor-arg value="20000" type="double"></constructor-arg> </bean> </property> </bean>



顺便复习一下,这里的三个Person类型的bean(person、person2、person3)的三个属性都是通过<property>标签进行注入的,即通过属性注入的,而Car类型的bean(car2)是通过<constructor-arg>标签进行注入的,即通过构造方法注入的。

  可以看到引入其他的bean的配置实在是太简单了,我们可以事先定义好要使用的bean,然后通过ref属性引用,即第一种配置方法;也可以通过<ref>标签,即第二种配置方法。这两种方式都是引用的我们事先定义好的bean,即先有了car2,然后直接通过ref属性进行引用。

内部bean,这种bean对外部是不可见的,即外部不能够使用它,相应的也可以不设置id和name属性(因为外面反正也用不了,(*^__^*) 嘻嘻……)。内部bean的定义可以使用我们上一篇文章中说的bean的配置方法进行定义,使用属性注入或者构造方法注入都是可以的。说了这么多,到底管不管用呢,下面看一下程序运行结果(大家看的时候可能看不完全图片,可以点击图片在新窗口看完整图片):

spring bean冲突配置_赋值

 可以看到person和person2这两个bean的输出中关于car的部分,和car2是一样的,你可能注意到了,price是0.0,这是因为我们的car2中也是0.0,我们就没有给car的price属性赋值,我们的配置文件中第三个参数是int类型的,也就是会赋值给maxSpeed属性。而person3中关于car的输出是和我们内部bean的定义是一致的。


  接下来让我们看一下使用构造方法注入的定义形式:



<!-- 通过构造器来配置bean --> <bean id="person4" class="com.study.spring.Person"> <constructor-arg value="Aces"></constructor-arg> <constructor-arg value="18"></constructor-arg> <constructor-arg ref="car2"></constructor-arg> <!--  <constructor-arg> <ref bean="car2"/> </constructor-arg>  --> </bean> <!-- 通过构造器来配置bean --> <bean id="person5" class="com.study.spring.Person"> <constructor-arg value="Aces"></constructor-arg> <constructor-arg value="18"></constructor-arg> <!-- 测试赋值null,null必须这么写,是专有标记 --> <constructor-arg> <null /> </constructor-arg> </bean> <!-- 级联赋值 --> <bean id="person6" class="com.study.spring.Person"> <constructor-arg value="Aces"></constructor-arg> <constructor-arg value="18"></constructor-arg> <constructor-arg ref="car2"></constructor-arg> <!-- 级联赋值,其实和属性注入是一样的,也是通过set方法,   注意:属性需要先初始化之后才可以对级联属性进行赋值,否则会有异常,   和struts2不同,struts2会自动的创建对象并为级联属性赋值  --> <property name="car.price" value="30000"></property> </bean> <!-- 这个bean的配置是有问题的,因为没有对car进行赋值,所以car是null, spring不会自动的创建一个car对象并对其赋值, 所以不能直接对car.price进行级联赋值  <bean id="person7" class="com.study.spring.Person"> <property name="name" value="Aces"></property> <property name="age" value="18"></property> <property name="car.price" value="30000"></property> </bean> -->



看一下person5的定义,赋值为null,必须要这么定义,这是null的专有标志。

属性需要先初始化之后才可以对级联属性进行赋值,否则会有异常,和struts2不同,struts2会自动的创建对象并为级联属性赋值。下面person7的定义就很好的说明了这个问题,person7的这种定义方式,我们没有为car赋值(其实他就是null),进行级联赋值的时候,就会抛出异常,当然了上面被我注释掉了,就是为了说明这个问题。下面给出一个把person7放开的一个运行结果截图:

spring bean冲突配置_spring_02

可  以看到什么输出都没有,上面的那两个输出是构造方法和set方法中添加的打印语句,因为我们前面已经说过了,IoC容器会在初始化的时候,创建所有的bean,当它创建person7的时候,因为我们没有初始化car属性,而是直接进行级联赋值,所以它抛出了异常。其实不管你是用属性注入还是构造方法注入,他们的结果是一样的,可以按照个人习惯,灵活使用。

  下面给一个person7注释掉之后的运行结果截图:

spring bean冲突配置_java_03

  不知道大家有没有注意到car2的price已经变成了30000.0了,为什么会这样,什么时候变的?请大家看一下person6的定义,有没有找到?

  可能有些人还在想怎么没有给出测试类,只是给出了测试结果,我开始是认为学习spring的肯定都是有一定java基础的,其实测试类非常简单,与《Spring学习系列之——第一章:Spring版本的HelloWorld》文章中给出的类似,获取bean,然后调用类的打印。下面一并给出来好了,省的大家再去翻找,测试类真心没内容呀。。。。测试类代码如下:

package com.study.spring;

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

public class Main {
	public static void main(String[] args) {
		
		//1.创建Spring的IOC容器对象,在创建容器的时候,完成了bean的初始化和属性的设置
		//ApplicationContext代表IOC容器,在初始化上下文的时候就实例化所有单例的bean
		//ClassPathXmlApplicationContext:是ApplicationContext接口的实现类,该类从类路径下来加载配置文件
		//FileSystemXmlApplicationContext:是ApplicationContext接口的实现类,该类从文件系统中加载配置文件
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		//2.从IOC容器获取bean实例
		HelloWorld helloWorld = (HelloWorld)ctx.getBean("helloWorld");
		//利用类型返回IOC容器中的bean,但要求IOC容器必须只能有一个该类型的Bean
		//HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
		
		//3.调用bean的方法
		helloWorld.hello();
		
		Car car = (Car)ctx.getBean("car");
		System.out.println(car);
		
		Car car2 = (Car)ctx.getBean("car2");
		System.out.println(car2);
		
		Car car3 = (Car)ctx.getBean("car3");
		System.out.println(car3);
		
		Person person = (Person)ctx.getBean("person");
		System.out.println(person);
		
		
		Person person2 = (Person)ctx.getBean("person2");
		System.out.println(person2);
		
		Person person3 = (Person)ctx.getBean("person3");
		System.out.println(person3);
		
		Person person4 = (Person)ctx.getBean("person4");
		System.out.println(person4);
		
		Person person5 = (Person)ctx.getBean("person5");
		System.out.println(person5);
		
		Person person6 = (Person)ctx.getBean("person6");
		System.out.println(person6);
		
//		Person person7 = (Person)ctx.getBean("person7");
//		System.out.println(person7);
	}
}



转载于:https://blog.51cto.com/acesdream/1641907