一、自动装配
通过配置default-autowire 属性,Spring IOC 容器可以自动为程序注入bean;默认是no,不启用自动装配;default-autowire 的类型有byName,byType,constructor;
byName:通过名称进行自动匹配;
byType:根据类型进行自动匹配;
constructor:和byType 类似,只不过它是根据构造方法注入而言的,根据类型,自动注入;
建议:自动装配机制慎用,它屏蔽了装配细节,容易产生潜在的错误;
1.新建工程Spring402-04;
2.新建类People:
package com.test.entity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class People {
private int id;
private String name;
private int age;
private Dog dog1;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 Dog getDog1() {
return dog1;
}
public void setDog1(Dog dog1) {
this.dog1 = dog1;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", age=" + age + ", dog1=" + dog1.getName() + "]";
}
}
3.新建类Dog:
package com.test.entity;
public class Dog {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4.修改Spring配置文件:
这里开启了自动装配,采用按照名字自动装配的方式。定义了两个Dog对象dog1和dog2,定义了People对象people1,这里people1中并没有对Dog对象dog1进行装配。
5.写测试方法:
@Test
public void test1() {
People people = (People) ac.getBean("people1");
System.out.println(people);
}
运行测试方法:
可以看到这里给我们进行了自动装配。因为People中Dog对象的名字是dog1,所以这里给我们自动装配了dog1对象。
2)按照类型自动装配,修改Spring配置文件为:
<?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"
default-autowire="byType">
<bean id="dog2" class="com.test.entity.Dog">
<property name="name" value="Tom"></property>
</bean>
<bean id="people1" class="com.test.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
</bean>
</beans>
这里改成了byType通过类型自动装配,并删除了刚才定义的dog1对象。因为这里是根据类型进行装配,dog1和dog2类型相同都是Dog类型,所以如果保留着dog1对象的话,就会因为不知道要装配哪一个对象而报错。
运行测试方法test1:
这里根据类型把dog2对象进行了自动装配。
3)根据构造函数自动装配:根据类型进行装配
修改People类,添加构造方法:
public People() {
super();
// TODO Auto-generated constructor stub
}
public People( Dog dog1) {
super();
System.out.println("constructor");
this.dog1 = dog1;
}
这里给People类添加了构造方法,这里第二个构造方法利用Dog对象进行构造。
4.修改Spring配置文件:
<?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"
default-autowire="constructor">
<bean id="dog2" class="com.test.entity.Dog">
<property name="name" value="Tom"></property>
</bean>
<bean id="people1" class="com.test.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
</bean>
</beans>
这里自动装配改成了constructor利用构造函数自动装配。
运行测试方法:
这里运行了People的第二个构造方法,按照这个构造方法里面参数的类型进行了自动装配。
二、方法注入
这里提出一个这样的问题:Dog类中每次调用get方法都获取一个新的dog对象。
1.修改Spring配置文件:
<?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="dog" class="com.test.entity.Dog">
<property name="name" value="Tom"></property>
</bean>
<bean id="people1" class="com.test.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
</bean>
</beans>
这里把自动装配去掉。修改People类:
package com.test.entity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class People {
private int id;
private String name;
private int age;
private Dog dog1;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 Dog getDog1() {
return dog1;
}
public void setDog1(Dog dog1) {
this.dog1 = dog1;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", age=" + age + ", dog1=" + dog1.getName() + "]";
}
}
先看一个测试方法:
@Test
public void test1() {
System.out.println(ac.getBean("dog")==ac.getBean("dog"));
}
运行这个测试方法,输出true。这里取了两次Dog对象实例,这两个对象是同一个对象,这是因为在默认情况下Spring的IOC容器中对象是单例的。现在要去每次获取到的狗是一条新的狗,就不能使用单例形式。修改配置文件如下:
<bean id="dog" class="com.test.entity.Dog" scope="prototype">
<property name="name" value="Tom"></property>
</bean>
默认情况下scope属性的值是singleton,是单例的。现在修改成prototype,实现多例。
运行一下test1测试方法,程序输出为false。这样的话,每次在IOC容器中获取dog对象都是一个新的对象。现在修改Spring配置文件:
<bean id="people1" class="com.test.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
<property name="dog1" ref="dog"></property>
</bean>
这里使用ref属性给dog对象注入值。
写测试方法:
@Test
public void test1() {
People people = (People) ac.getBean("people1");
People people2 = (People) ac.getBean("people1");
System.out.println(people.getDog1()==people2.getDog1());
}
运行这个测试方法,程序输出true。在配置文件中People类默认是单例的,所以这里people和people2是同一个对象,对于同一个对象的两次加载,Spring只调用一次Dog类的getDog方法,所以这里两个对象装配的dog实例是相同的。现在要求虽然这两个对象是相同的,但是给他们装配不同的dog对象,也就是实现Spring动态的调用getDog方法。这里要修改People类为:
package com.test.entity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public abstract class People {
private int id;
private String name;
private int age;
private Dog dog1;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 abstract Dog getDog1();
public void setDog1(Dog dog1) {
this.dog1 = dog1;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", age=" + age + ", dog1=" + dog1.getName() + "]";
}
}
这里把People类定义成了抽象类,把getDog方法定义成了抽象方法。
修改Spring配置文件:
<bean id="people1" class="com.test.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
<lookup-method name="getDog1" bean="dog"/>
</bean>
这里使用<lookup-method>标签实现方法的动态注入,每次获取people1对象时Spring都会动态的去调用一次getDog1方法,这样因为Dog类的多例的,每次获取到的dog对象都是不同的。测试方法输出为false。
方法注入并不是常用。
三、方法替换
所谓方法替换就是Spring调用其它方法,而不是调用它本应该调用的方法。
修改People类如下:
package com.test.entity;
public class People {
private int id;
private String name;
private int age;
private Dog dog;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 Dog getDog() {
Dog dog = new Dog();
dog.setName("Jack");
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", age=" + age + ", dog=" + dog.getName() + "]";
}
}
我们这里给People类指定了Dog对象为名为Jack的狗。
定义一个类People2:
package com.test.entity;
import java.lang.reflect.Method;
import org.springframework.beans.factory.support.MethodReplacer;
public class People2 implements MethodReplacer{
@Override
public Object reimplement(Object arg0, Method arg1, Object[] arg2) throws Throwable {
Dog dog = new Dog();
dog.setName("Tom");
return dog;
}
}
People2实现了接口MethodReplacer,并重写了其中的方法reimplement,在这个方法中返回一个名为Tom的狗。
修改Spring配置文件为:
<?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="people1" class="com.test.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
<replaced-method name="getDog" replacer="people2"></replaced-method>
</bean>
<bean id="people2" class="com.test.entity.People2"></bean>
</beans>
这里实现people1时,使用people2中的方法替换getDog方法。
测试方法:
@Test
public void test1() {
People people = (People) ac.getBean("people1");
System.out.println(people.getDog().getName());
}
程序运行结果为Tom,这里实现了方法替换。使用了People2中的方法替换了People1中的getDog方法。
Spring中方法替换使用的也非常少。