<框架篇(2)>Spring框架中实例对象(bean)的创建方式(一)

来源:互联网 发布:手机机顶盒遥控器软件 编辑:程序博客网 时间:2024/06/02 04:35

在前一篇文章中简单的介绍了SpringIoc(依赖注入/控制反转)的原理及为什么要使用IoC,并且以一个简单的例子说明了在使用Spring框架时Bean的创建和使用的方式。事实上,Spring提供了丰富的创建实例Bean的方式,大致上可以分为:指定全类名、工厂方法、基于注解,文章先讲解通过指定全类名的方式创建Bean。
首先创建两个bean类,一个为Car.jave,另一个为Person.java,代码如下:

package cn.pb.bean;public class Car {    private String brand;    private String local;    public double price;    private int maxSpeed;    public Car(String brand, String local, double price) {        super();        this.brand = brand;        this.local = local;        this.price = price;    }    public Car(String brand, String local, int maxSpeed) {        super();        this.brand = brand;        this.local = local;        this.maxSpeed = maxSpeed;    }    @Override    public String toString() {        return "Car [brand=" + brand + ", local=" + local + ", price=" + price                + ", maxSpeed=" + maxSpeed + "]";    }   }
package cn.pb.bean;public class Person {    private String name;    private int age;    private Car car;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public Car getCar() {        return car;    }    public void setCar(Car car) {        this.car = car;    }    @Override    public String toString() {        return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";    }   }

注意两个bean的不同,在Car.java中,有两个重载的带参构造方法,没有无参的构造方法,4个属性没有对应的getter和setter,因此只能通过两个带参构造方法实例化对象。而在Person.java中,所有的属性都有对应的getter和setter,并默认有无参的构造方法,这两种代表了我们在创建对象时的不同的方法,重写ToString()方法方便查看创建的实例对象。之所以把他们分开,是因为通过Spring Bean Configuration File来创建Bean的方式也是不同的。
一,Spring容器创建Car实例

<bean id="car" class="cn.pb.bean.Car">    <constructor-arg value="Audi"></constructor-arg>    <constructor-arg value="shanghai"></constructor-arg>    <constructor-arg value="3000000"></constructor-arg></bean>

通过此种方法创建Car实例时,Spring容器会找到cn.pb.bean.Car类中的带参的构造方法并为参数赋值,创建Car对象,为了避免顺序混乱,也可以如下写:

<bean id="car" class="cn.pb.bean.Car">    <constructor-arg value="Audi" index="0"></constructor-arg>    <constructor-arg value="shanghai" index="1"></constructor-arg>    <constructor-arg value="3000000" index="2"></constructor-arg></bean>

可能你还会有疑问,在Car.java中有两个带参的构造方法,他们的第三个参数是不同的,它找的是哪一个呢?可先输出下结果,测试代码如下:

package cn.pb.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.pb.bean.Car;public class ConfigurationTest {    public static void main(String[] args) {        ApplicationContext ctx=new ClassPathXmlApplicationContext("ConfigurationTest.xml");        Car car=(Car) ctx.getBean("car");        System.out.println(car);    }}

输出结果:Car [brand=Audi, local=shanghai, price=3000000.0, maxSpeed=0]
可以看出,默认的是第一个构造方法,这与Car中构造方法的顺序有关。同时要注意,Spring会自动将int型转换为double,却不会将idouble转换为int,因此即使将构造方法Car(String brand, String local, int maxSpeed)置于前面,当constructor-arg标签index=”2”的项值设置为double型,创建的也是Car(String brand, String local, double price)对象。为了避免出现不必要的错误,可添加type属性:

<bean id="car" class="cn.pb.bean.Car">        <constructor-arg value="Audi" type="String"></constructor-arg>        <constructor-arg value="shanghai" type="String"></constructor-arg>        <constructor-arg value="300000" type="double"></constructor-arg>    </bean>

此时就可以根据类型创建对应的对象,以区分重载的构造方法,注意type值得字母大小写与类型的对应顺序,否则会报错。
也可以将value属性提出来放在一个单独的标签中,当值中出现特殊字符如”>”、”<”时会报错,此时可以用

<bean id="car1" class="cn.pb.bean.Car">    <constructor-arg>        <value><![CDATA[>BMW<]]></value>    </constructor-arg>    <constructor-arg value="guangzhou"></constructor-arg>    <constructor-arg type="int">        <value>290</value>    </constructor-arg></bean>

实例化结果:Car [brand=>BMW<, local=guangzhou, price=0.0, maxSpeed=290]
二,Spring容器创建Person实例

<bean id="person" class="cn.pb.bean.Person">    <property name="name" value="zhangsan"></property>    <property name="age" value="24"></property>    <property name="car">        <bean class="cn.pb.bean.Car">            <constructor-arg value="Audi" type="String"></constructor-arg>            <constructor-arg value="shanghai" type="String"></constructor-arg>            <constructor-arg value="300000" type="double"></constructor-arg>        </bean>    </property></bean>

实例化结果:Person [name=zhangsan, age=24, car=Car [brand=Audi, local=shanghai, price=300000.0, maxSpeed=0]]
用此种方法创建实例实际上是通过无参的构造方法来创建对象,通过每个属性所对应的setter方法类进行赋值的,因此在Person类中必须有无参的构造方法和对应的setter,同时应该注意property节点中name属性的值要与set方法后的名字一致,例如:name=”age”,在Person中的方法是setAge(int age),因为是通过反射机制来进行赋值的。此对象中有一个属性是对对象car的引用,因此也可以如下写:

<bean id="person" class="cn.pb.bean.Person">    <property name="name" value="zhangsan"></property>    <property name="age" value="24"></property>    <property name="car">        <ref bean="car"/>    </property></bean>

创建的过程还有一种简化写法,首先在xml中引入p命名空间,则person还可以改写为:

<bean id="person" class="cn.pb.bean.Person" p:age="24" p:name="zhangsan" p:car-ref="car"></bean>

三,在此之外还有自动装配的方法,可以使用autowire属性指定自动装配的方式,byName根据bean的id名称和当前bean的setter风格的属性名进行自动装配 ,例如:

<bean id="person2" class="cn.pb.bean.Person" p:age="30" p:name="Cendy" autowire="byName"></bean>

实例化结果:Person [name=Cendy, age=30, car=Car [brand=Audi, local=shanghai, price=300000.0, maxSpeed=0]]
因为在Person类中是setCar,所以这里会自动装配id名称为car的Bean,而不会装配id名称为car1的Bean。
byType则根据bean的类型当前bean的属性类型进行自动装配,若IoC容器中有1个以上的类型匹配的bean则抛出异常,如:

<bean id="person2" class="cn.pb.bean.Person" p:age="30" p:name="Cendy" autowire="byType"></bean>

此时会抛出异常,因为创建创建了id=”car”和id=”car1”两个Car类型的实例,注掉其中一个如注掉car1,则实例化结果:

Person [name=Cendy, age=30, car=Car [brand=Audi, local=shanghai, price=300000.0, maxSpeed=0]]

以上介绍了Spring中Bean的创建方式,特别的,如果两个实例之间存在继承关系,比如id=”person3”的实例与id=”person”实例对象的属性除姓名之外都一样,则可以使用bean的parent属性指定继承哪个bean的属性,创建person3的语句可以如下写:

<bean id="person3" p:name="Tom" parent="person"></bean>

id=”person”实例:Person [name=zhangsan, age=24, car=Car [brand=Audi, local=shanghai, price=300000.0, maxSpeed=0]]
id=”person3”实例:Person [name=Tom, age=24, car=Car [brand=Audi, local=shanghai, price=300000.0, maxSpeed=0]]
当指定的bean中有autowire属性时,将不会继承该属性。给bean添加属性abstract=”true”,则此bean只能用来被继承而不能被IoC实例化 ,若某个bean的class属性没有指定,则该bean必须是一个抽象bean。

0 0