Bean的作用域
默认情况下,bean的作用域为单例模式(singleton):
在applicationContext创建时,就将配置文件中的bean加载完毕;
在调用getBean时,从applicationContext中获取;
也就是说,在整个应用程序中,bean只存在一个实例,下面写一段代码测试一下,写一个Car类,有一个Name字段:
package cn.net.bysoft.lesson4;
public class Car {
public Car() {
}
@Override
public String toString() {
return "Car [name=" + name + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
}
在配置文件中,配置这个Car的bean元素:
<bean id="car" class="cn.net.bysoft.lesson4.Car">
</bean>
@Test
public void testScopeIsDefault() {
// 在Spring容器初始化时就生成了bean对应的对象。
// 在调用时,从Spring容器中get一个对象,这个对象是单例的。
Car car = (Car) ctx.getBean("car");
car.setName("Audi");
Car car1 = (Car) ctx.getBean("car");
car1.setName("BMW");
// get到的对象都会修改这个单例的bean。
System.out.println(car);
System.out.println(car1);
/**
* output:
* Car [name=BMW]
* Car [name=BMW]
* */
}
测试发现,对car设置的name值被car1覆盖了,也就是说,car与car1实际是使用的同一个car实例,car==car1。
可以改变bean的作用域来解决此问题,将scope=prototype:
<bean id="car2" class="cn.net.bysoft.lesson4.Car" scope="prototype">
</bean>
@Test
public void testScopeIsPrototype() {
// 设置了bean的scope=prototype后
// 在Spring容器初始化时不会自动生成bean对应的对象
// 而是在get时生成对象,对象不是单例的。
Car car = (Car) ctx.getBean("car2");
car.setName("Audi");
Car car1 = (Car) ctx.getBean("car2");
car1.setName("BMW");
System.out.println(car);
System.out.println(car1);
/**
* output:
* Car [name=Audi]
* Car [name=BMW]
* */
}
Bean的生命周期
正常情况下,spring加载bean时,首先会调用构造函数,接着对property赋值时调用setter方法。
如果需要对bean有更多的控制,可以设置init-method与destroy-method属性,修改一下car对象,加入init与destory方法:
package cn.net.bysoft.lesson4;
public class Car {
public Car() {
System.out.println("1.执行了构造函数。");
}
public void init() {
System.out.println("3.执行初始化。");
}
public void destory() {
System.out.println("5.执行销毁。");
}
@Override
public String toString() {
System.out.println("4.使用bean方法。");
return "Car [name=" + name + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("2.调用setter方法。");
this.name = name;
}
private String name;
}
在配置文件中为bean配置init-method与destory-method:
<bean id="car3" class="cn.net.bysoft.lesson4.Car" init-method="init"
destroy-method="destory" scope="singleton">
<property name="name" value="Audi"></property>
</bean>
在进行测试,看看各个方法的执行顺序:
@Test
public void testCycle() {
Car car = (Car) ctx.getBean("car3");
System.out.println(car);
ctx.close();
}
执行了构造函数
执行了setter()方法
执行了init()方法
执行了destory()方法
使用bean的后置处理器
上面的做法是为单个类进行更多的初始化控制,还可以配置全局的初始化控制,做法为,创建一个类使用实现BeanPostProcessor接口,将该类配置到spring配置文件中即可:
package cn.net.bysoft.lesson4;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
// 后置初始化处理
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("after..." + bean.getClass() + ", " + beanName);
return bean;
}
@Override
// 前置初始化处理
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("before..." + bean.getClass() + ", " + beanName);
return bean;
}
}
<bean id="car4" class="cn.net.bysoft.lesson4.Car" init-method="init"
destroy-method="destory" scope="singleton">
<property name="name" value="BMW"></property>
</bean>
<bean class="cn.net.bysoft.lesson4.MyBeanPostProcessor"></bean>
@Test
public void testBeanPostProcessor() {
Car car = (Car) ctx.getBean("car4");
System.out.println(car);
ctx.close();
}
通过结果可以看到,配置的处理器before在init方法前被调用,after在init方法后调用。