Spring IOC容器可以实现Bean的自动装配,需要做的仅仅是在< bean >的autowire属性里指定自动装配的模式。
在实际的项目中一般很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。
根据属性名称进行自动装配,可以进行如下的改动。
<bean id="car" class="com.yfyzwr.spring.beans.Car"><!-- id改为car -->
<property name="brand" value="红旗"></property>
<property name="price" value="123456.78"></property>
</bean>
<bean id="Person" class="com.yfyzwr.spring.beans.Person" autowire="byName">
<property name="name" value="金三胖"></property>
<property name="age" value="30"></property>
<!-- 这里没有为car属性指定初始值 -->
</bean>
从输出结果可以得知Person类实例的car属性已经被成功赋值。
使用byName的自动装配方式,必须保证所依赖Bean的id名称和当前Bean的属性名称完全相同。
根据属性类型进行自动装配,可以进行如下的改动。
<bean id="Car" class="com.yfyzwr.spring.beans.Car">
<property name="brand" value="红旗"></property>
<property name="price" value="123456.78"></property>
</bean>
<bean id="Person" class="com.yfyzwr.spring.beans.Person" autowire="byType">
<property name="name" value="金三胖"></property>
<property name="age" value="30"></property>
<!-- 这里没有为car属性指定初始值 -->
</bean>
从输出结果可以得知Person类实例的car属性已经被成功赋值
使用byType的自动装配方式,必须保证所依赖Bean的class的类型和当前Bean的属性的类型完全相同。
如果我们为相同的class配置两个(或多个)bean的话,那么byType自动装配的结果有如何呢?
<bean id="Car1" class="com.yfyzwr.spring.beans.Car">
<property name="brand" value="红旗"></property>
<property name="price" value="123456.78"></property>
</bean>
<bean id="Car2" class="com.yfyzwr.spring.beans.Car">
<property name="brand" value="红旗"></property>
<property name="price" value="123456.78"></property>
</bean>
<bean id="Person" class="com.yfyzwr.spring.beans.Person" autowire="byType">
<property name="name" value="金三胖"></property>
<property name="age" value="30"></property>
<!-- 这里没有为car属性指定初始值 -->
</bean>
此时运行的结果却是提示NoUniqueBeanDefinitionException错误(Bean的声明不唯一)。
如果容器中有两个(或多个)与所依赖Bean的类型一致的Bean,那么在这种情况下Spring将无法判定哪个Bean最合适该属性, 所以不能执行自动装配。
Spring可以在< bean >元素的 scope 属性里设置 Bean 的作用域。
默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一的一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例。该作用域被称为 singleton, 它是所有 Bean 的默认作用域。
修改Car类的实现。
public class Car {
private String brand;
private double price;
public Car() {
System.out.println("car Constructor……");
}
public void setBrand(String brand) {
System.out.println("setBrand");
this.brand = brand;
}
public void setPrice(double price) {
System.out.println("setPrice");
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
}
修改main方法。
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Car car1 = (Car)context.getBean("Car");
Car car2 = (Car)context.getBean("Car");
System.out.println(car1.hashCode());
System.out.println(car2.hashCode());
context.close();
运行程序,查看结果。
car Constructor……
setBrand
setPrice
363391
363391
对于默认的singleton作用域,在容器加载bean的时候会调用其构造函数和setter函数,对其实例化。之后的所有对bean的使用都是同一实例对象。
修改xml文件。
<bean id="Car" class="com.yfyzwr.spring.beans.Car" scope="prototype">
<property name="brand" value="baoma"></property>
<property name="price" value="123"></property>
</bean>
运行程序,查看结果。
car Constructor……
setBrand
setPrice
car Constructor……
setBrand
setPrice
363391
617995
对于protoType作用域,每次调用getBean()都会得到一个新的实例对象。实例对象不再是容器加载Bean的时候创建,而是调用getBean()的时候才创建。
Spring IOC 容器对 Bean 的生命周期进行管理的过程:
可以在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化方法和销毁方法。
修改Car类的实现,添加init()和destroy()方法。
public void init(){ //方法名可以任意取名
System.out.println("init...");
}
public void destroy(){ //方法名可以任意取名
System.out.println("destroy...");
}
修改xml文件的实现。
<bean id="Car" class="com.yfyzwr.spring.beans.Car"
init-method="init" destroy-method="destroy">
<property name="brand" value="baoma"></property>
<property name="price" value="123"></property>
</bean>
运行程序,查看结果。
car Constructor……
setBrand
setPrice
init…
Car [brand=baoma, price=123.0]
destroy…
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。Bean的后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一某个实例。
其典型应用是:检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性。
对Bean的后置处理器而言, 需要实现org.springframework.beans.factory.config.BeanPostProcessor接口,该接口有两个方法需要被复写,在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给这两个方法。
新建MyBeanPostProcessor类并复写方法。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("Car".equals(beanName)){
System.out.println("postProcessBeforeInitialization" + bean + beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("Car".equals(beanName)){ //beanName是指bean的id属性
System.out.println("postProcessAfterInitialization" + bean + beanName);
Car car = new Car();
car.setBrand("红旗");
car.setPrice(789);
return car;
}
return bean;
}
}
为MyBeanPostProcessor添加bean配置,添加如下语句。
<bean class="com.yfyzwr.spring.beans.MyBeanPostProcessor"></bean>
运行程序,查看结果。
car Constructor……
setBrand
setPrice
postProcessBeforeInitializationCar [brand=baoma, price=123.0]Car
init…
postProcessAfterInitializationCar [brand=baoma, price=123.0]Car
car Constructor……
setBrand
setPrice
Car [brand=红旗, price=789.0]
destroy…
从输出结果可以得知,我们通过BeanPostProcessor 接口可以对bean的实例进行自定义的操作。