参考:http://www.cnblogs.com/xrq730/p/4912876.html
https://my.oschina.net/itblog/blog/205172
Set注入
spring最简单的注入方式
定义一个Person和一个Family:
public class Person {
private String personName;
private int personAge;
public String getPersonName() {
return personName;
}
public void setPersonName(String personName) {
this.personName = personName;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public int getPersonAge() {
return personAge;
}
public void setPersonAge(int personAge) {
this.personAge = personAge;
}
public Person(String personName, int personAge) {
super();
this.personName = personName;
this.personAge = personAge;
}
public String toString() {
return "personName=" + personName + ", personAge=" + personAge;
}
}
public class Family {
private Person person;
private String familyName;
public Family(Person person, String familyName) {
super();
this.person = person;
this.familyName = familyName;
}
public String toString() {
return "person=" + person + ", familyName=" + familyName;
}
}
applicationContext.xml
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="person" class="entity.Person">
<property name="personName" value="Alice"></property>
<property name="personAge" value="23"></property>
</bean>
</beans>
name属性表示Person类的变量名,value对应的就是我们赋给它的值,注意的是如果name对应的变量是一个类,那么value要用ref代替(见后面的Family的配置)
测试:
public static void main(String[] args) throws Exception {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Person person1 = (Person)ac.getBean("person");
Person person2 = (Person)ac.getBean("person");
System.out.println(person1.toString());
System.out.println(person1 == person2);
}
运行结果是:
personName=Alice, personAge=23
true
set方法注入的前提条件是Person类一定要有set方法,并且通过比较person1=person2我们发现,Spring默认以单例的形式给开发者构造出指定的bean,需要注意的是:
(1)同一个applicationContext.xml文件里面不可以有两个相同id的bean
(2)ClassPathXmlApplicationContext中有一个可变长度的构造函数,用于加载多个.xml,如果多个.xml文件里面有相同id的bean,后加载的会覆盖先加载的。
构造器注入
这种方式的注入是指带有参数的构造函数注入,比如这里的Family,我创建了两个成员变量,但是没有设置set方法,只有(这种方法一定要有)带有参数的构造方法,applicationContext.xml:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="family" class="entity.Family">
<constructor-arg name="person" ref="person" />
<constructor-arg name="familyName" value="friendly" />
</bean>
<bean id="person" class="entity.Person">
<property name="personName" value="Alice"></property>
<property name="personAge" value="23"></property>
</bean>
</beans>
测试:
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Family family=(Family)ac.getBean("family");
System.out.println(family.toString());
输出结果:
person=personName=Alice, personAge=23, familyName=friendly
这里故意把family的定义写在person的定义上面,说明即使前面的beanA持有beanB的引用,把beanA定义在beanB前面也不影响
静态工厂方法
使用静态工厂方法创建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;
}
public void sayHello() {
// TODO Auto-generated method stub
System.out.println(msg + ",喵~喵~");
}
}
public class Dog implements Animal {
private String msg;
//依赖注入时必须的setter方法
public void setMsg(String msg){
this.msg = msg;
}
public void sayHello() {
// TODO Auto-generated method stub
System.out.println(msg + ",旺~旺~");
}
}
再写一个工厂类:
public class AnimalFactory {
public Animal getAnimal(String type){
if ("cat".equalsIgnoreCase(type)){
return new Cat();
} else {
return new Dog();
}
}
}
applicationContext.xml
<!-- 配置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完全相同,这是因为两个实例都使用同一个静态工厂类、同一个静态工厂方法产生得到的。只是为这个静态工厂方法指定的参数不同,使用元素来为静态工厂方法指定参数
测试:
Animal cat=ac.getBean("cat",Cat.class);
cat.sayHello();
Animal dog=ac.getBean("dog",Dog.class);
dog.sayHello();
输出:
小猫,喵~喵~
小狗,旺~旺~
使用静态工厂方法创建实例时必须提供工厂类和产生实例的静态工厂方法。通过静态工厂方法创建实例时需要对Spring配置文件做如下改变;
(1)class属性不在是Bean实例的实现类,而是生成Bean实例的静态工厂类
(2)使用factory-method指定生产Bean实例的静态工厂方法
(3)如果静态工厂方法需要参数,使用元素为其配置
当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为Bean实例,在这个过程中,Spring不再负责创建Bean实例,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>
最后测试结果和前面一样
上面四种方法比较常用的是前两种方法
补充:
Bean的作用域和生命周期:
1、scope表示的是bean的作用域,有prototype、request、session、singleton四种,其中singleton是默认的,表示单例。prototype表示每次创建都会产生一个bean实例。request和session只在web项目中才会用,其作用域就和web中的request和session一样
2、lazy-init表示的是bean的生命周期,默认为false。当scope=singleton时,bean会在 配置装载文件时实例化,如果希望bean在产生时才实例化,可以把lazy-init设置为true。当scope=prototype时,在产生bean时才会实例化它。补充一点,如果希望该配置文件中所有的bean都延迟初始化,则应该在beans根节点中使用lazy-init=”true”