您的位置:首页 > 编程语言 > Java开发

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

2017-05-14 20:34 453 查看
在前一篇文章中简单的介绍了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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring 框架 bean 对象
相关文章推荐