Spring4.0学习笔记004——Bean的配置二(基于XML文件)

1. bean的自动装配

Spring IOC容器可以实现Bean的自动装配,需要做的仅仅是在< bean >的autowire属性里指定自动装配的模式。

在实际的项目中一般很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。

1-1. byName

根据属性名称进行自动装配,可以进行如下的改动。

    <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的属性名称完全相同。

1-2. byType

根据属性类型进行自动装配,可以进行如下的改动。

    <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最合适该属性, 所以不能执行自动装配。

2. bean的作用域

Spring可以在< bean >元素的 scope 属性里设置 Bean 的作用域。

2-1. singleton

默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一的一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例。该作用域被称为 singleton, 它是所有 Bean 的默认作用域。

  1. 修改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 + "]";
        }
    
    }
  2. 修改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();
  3. 运行程序,查看结果。

    car Constructor……
    setBrand
    setPrice
    363391
    363391


对于默认的singleton作用域,在容器加载bean的时候会调用其构造函数和setter函数,对其实例化。之后的所有对bean的使用都是同一实例对象。

2-2. protoType

  1. 修改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>
  2. 运行程序,查看结果。

    car Constructor……
    setBrand
    setPrice
    car Constructor……
    setBrand
    setPrice
    363391
    617995


对于protoType作用域,每次调用getBean()都会得到一个新的实例对象。实例对象不再是容器加载Bean的时候创建,而是调用getBean()的时候才创建。

3. bean的生命周期

Spring IOC 容器对 Bean 的生命周期进行管理的过程:

  • 通过构造器或工厂方法创建 Bean 实例。
  • 为 Bean 的属性设置值或者是对其他 Bean 的引用。
  • 调用 Bean 的初始化方法。
  • Bean 可以被使用了。
  • 当容器关闭时, 调用 Bean 的销毁方法。

3-1. bean的初始化和销毁

可以在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化方法和销毁方法。

  1. 修改Car类的实现,添加init()和destroy()方法。

    public void init(){                             //方法名可以任意取名
        System.out.println("init...");
    }
    
    public void destroy(){                          //方法名可以任意取名
        System.out.println("destroy...");
    }
  2. 修改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>
  3. 运行程序,查看结果。

    car Constructor……
    setBrand
    setPrice
    init…
    Car [brand=baoma, price=123.0]
    destroy…

3-2. Bean的后置处理器

Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。Bean的后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一某个实例。

其典型应用是:检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性。

对Bean的后置处理器而言, 需要实现org.springframework.beans.factory.config.BeanPostProcessor接口,该接口有两个方法需要被复写,在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给这两个方法。

  1. 新建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;
        }
    }
  2. 为MyBeanPostProcessor添加bean配置,添加如下语句。

    <bean class="com.yfyzwr.spring.beans.MyBeanPostProcessor"></bean>
  3. 运行程序,查看结果。

    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的实例进行自定义的操作。

你可能感兴趣的:(spring)