上一篇中简单了说了一下使用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的配置方法进行定义,使用属性注入或者构造方法注入都是可以的。说了这么多,到底管不管用呢,下面看一下程序运行结果(大家看的时候可能看不完全图片,可以点击图片在新窗口看完整图片):
接下来让我们看一下使用构造方法注入的定义形式:
<!-- 通过构造器来配置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放开的一个运行结果截图:
下面给一个person7注释掉之后的运行结果截图:
可能有些人还在想怎么没有给出测试类,只是给出了测试结果,我开始是认为学习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