Spring基于xml注入bean的几种方式
- Set方法注入
- 构造器注入
- 静态工厂注入
- 实例工厂
构造器注入
public class AccountServiceImpl implements IAccountService {
//如果是经常变化的数据,并不适用于注入的方式
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name,Integer age,Date birthday){
this.name = name;
this.age = age;
this.birthday = birthday;
}
public void saveAccount(){
System.out.println("service中的saveAccount方法执行了。。。"+name+","+age+","+birthday);
}
}
构造函数注入
- 使用的标签:constructor-arg
- 标签出现的位置:bean标签的内部
- 标签中的属性
-
- type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
- index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
- name:用于指定给构造函数中指定名称的参数赋值
- value:用于提供基本类型和String类型的数据
- ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
<bean id="accountService" class="com.lp.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="泰斯特"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!-- 配置一个日期对象 -->
<bean id="now" class="java.util.Date"></bean>
Set方法注入
public class AccountServiceImpl2 implements IAccountService {
//如果是经常变化的数据,并不适用于注入的方式
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void saveAccount(){
System.out.println("service中的saveAccount方法执行了。。。"+name+","+age+","+birthday);
}
}
set方法注入
- 涉及的标签:property
- 出现的位置:bean标签的内部
- 标签的属性
-
- name:用于指定注入时所调用的set方法名称
- value:用于提供基本类型和String类型的数据
- ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
<!-- 配置一个日期对象 -->
<bean id="now" class="java.util.Date"></bean>
<bean id="accountService2" class="com.lp.service.impl.AccountServiceImpl2">
<property name="name" value="TEST" ></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
静态工厂注入
使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类。因为Spring需要知道是用哪个工厂来创建Bean实例。另外,还需要使用factory-method来指定静态工厂方法名,Spring将调用静态工厂方法(可能包含一组参数),来返回一个Bean实例,一旦获得了指定Bean实例,Spring后面的处理步骤与采用普通方法创建Bean实例则完全一样。需要注意的是,当使用静态工厂方法来创建Bean时,这个factory-method必须要是静态的。
先定义一个接口,静态方法产生的将是该接口的实例:
public interface Animal {
public void sayHello();
}
public class Cat implements Animal {
private String msg;
//依赖注入时必须的setter方法
public void setMsg(String msg){
this.msg = msg;
}
@Override
public void sayHello(){
System.out.println(msg + ",喵~喵~");
}
}
public class Dog implements Animal {
private String msg;
//依赖注入时必须的setter方法
public void setMsg(String msg){
this.msg = msg;
}
@Override
public void sayHello(){
System.out.println(msg + ",旺~旺~");
}
}
下面的AnimalFactory工厂中包含了一个getAnimal的静态方法,该方法将根据传入的参数决定创建哪个对象。这是典型的静态工厂设计模式。
public clas AnimalFactory {
public static Animal getAnimal(String type){
if ("cat".equalsIgnoreCase(type)){
return new Cat();
} else {
return new Dog();
}
}
}
如果需要指定Spring使用AnimalFactory来产生Animal对象,则可在Spring配置文件中作如下配置:
<!-- 配置AnimalFactory的getAnimal方法,使之产生Cat -->
<bean id="cat" class="com.abc.AnimalFactory" factory-method="getAnimal">
<!-- 配置静态工厂方法的参数,getAnimal方法将产生Cat类型的对象 -->
<constructor-arg value="cat" />
<!-- 通过setter注入的普通属性 -->
<property name="msg" value="猫猫" />
</bean>
<!-- 配置AnimalFactory的getAnimal方法,使之产生Dog -->
<bean id="dog" class="com.abc.AnimalFactory" factory-method="getAnimal">
<!-- 配置静态工厂方法的参数,getAnimal方法将产生Dog类型的对象 -->
<constructor-arg value="dog" />
<!-- 通过setter注入的普通属性 -->
<property name="msg" value="狗狗" />
</bean>
从上面的配置可以看出:cat和dog两个Bean配置的class和factory-method完全相同,这是因为两个实例都使用同一个静态工厂类、同一个静态工厂方法产生得到的。只是为这个静态工厂方法指定的参数不同,使用<constructor-arg />元素来为静态工厂方法指定参数。
注意这里的两个bean不是AnimalFactory对象的bean,而是cat和dog对象的bean,因为是静态工厂,里面的方法是静态方法,所以是不需要实例对象就可调用对应的方法
主程序获取cat和dog两个Bean实例的方法不变,同样只需要调用Spring容器的getBean()即可:
public class Test {
public static void main(String args[]){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Animal a1 = context.getBean("cat", Animal.class);
a1.sayHello();//猫猫,喵~喵~
Animal a2 = context.getBean("dog", Animal.class);
a2.sayHello();//狗狗,旺~旺~
}
}
使用静态工厂方法创建实例时必须提供工厂类和产生实例的静态工厂方法。通过静态工厂方法创建实例时需要对Spring配置文件做如下改变;
- class属性不在是Bean实例的实现类,而是生成Bean实例的静态工厂类
- 使用factory-method指定生产Bean实例的静态工厂方法
- 如果静态工厂方法需要参数,使用<constructor-arg />元素为其配置
当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为Bean实例,在这个过程中,Spring不再负责创建Bean实例,Bean实例是由用户提供的静态工厂方法提供的。
实例工厂
实例工厂方法与静态工厂方法只有一点不同:调用静态工厂方法只需要使用工厂类即可,调用实例工厂方法则必须使用工厂实例。
所以在Spring配置上也只有一点区别:配置静态工厂方法指定静态工厂类,配置实例工厂方法则指定工厂实例。同样是上面的例子将AnimalFactory修改为:
public clas AnimalFactory {
public Animal getAnimal(String type){ //这里仅仅是去掉了static关键字
if ("cat".equalsIgnoreCase(type)){
return new Cat();
} else {
return new Dog();
}
}
}
Spring文件修改为:
<!-- 先配置工厂类 -->
<bean id="animalFactory" class="com.abc.AnimalFactory" />
<!-- 这里使用factory-bean指定实例工厂类对象 -->
<bean id="cat" factory-bean="animalFactory" factory-method="getAnimal">
<!-- 同样指定factory-method的参数 -->
<constructor-arg value="cat" />
<property name="msg" value="猫猫" />
</bean>
<bean id="dog" factory-bean="animalFactory" factory-method="getAnimal">
<constructor-arg value="dog" />
<property name="msg" value="狗狗" />
</bean>
这上面的唯一区别就是先创建了一个animalFactory对象的bean,然后通过这个属性factory-bean="animalFactory"指定工厂实例,然后通过这个实例对象的bean来创建cat和dog对象的bean