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

spring学习笔记:bean的配置

2009-08-10 15:05 471 查看
从Spring IOC容器中获取一个bean很简单,正如前面看到的,context.getBean("bean name");
关键是配置bean, 我们前面配置了一个叫做myBook的bean;
<bean id="myBook" class="model.Book">
<property name="id" value="000002" />
<property name="name" value="Thinking in java" />
<property name="author" value="Bruce Eckel" />
<property name="price" value="2222" />
</bean>
 
IOC容器在装配这个bean的时候,先调用Book的默认构造函数Book()创造一个Book对象,然后通过反射调用book的各个set方法为book的属性赋值,最后这个bean会被缓存起来等待被使用。

现在就来说一下bean的配置.
最简单的情形:
<bean id="dt" class="java.util.Date"></bean>

这样写会调用Date的默认构造函数, 获得运行时的时间.
属性注入: 就像前面的myBook一样,需要指出的两点是:
1,需要注入的属性必须有setter方法;2,必须有默认的构造函数; 原因已经说了,ioc容器在装配这个bean的时候,先调用默认构造函数创造一个对象,然后通过反射调用各个set方法为属性赋值.比如我们前面的Book类, 如果你添加了一个构造函数,如:
public Book(String id, String name, String author, float price)

则要同时添加一个默认构造函数 public Book(){},因为java语言规范中如果你没有提供构造函数, 则jvm会自动添加一个默认的构造方法,但是如果你提供了构造寒暑,则jvm不会添加构造函数.所以如果你没有给Book提供默认构造函数,则Ioc容器启动的时候会报错Could not instantiate bean class [model.Book]: No default constructor
found;你可以亲自测试一下.
构造函数注入: 如果我们给Book指定了一个构造函数,像这样:

public Book(String id, String name, String author, float price){
this.id = id;
this.name = name;
this.author = author;
this.price = price;
}
//getter setter忽略


那么就可以这样来配置bean:
<bean id="myBook1" class="model.Book">
<constructor-arg index="0" value="000002" />
<constructor-arg index="1" value="Thinking in java" />
<constructor-arg index="2" value="Bruce Eckel" />
<constructor-arg index="3" value="2222" />
</bean>

需要注意的是, 你给出的构造参数顺序要与构造函数一致.因为构造函数可以由多个.

工厂方法注入: 如果我们为Book提供一个工厂专门生产Book, 比如有这样一个非静态工厂:
package model.factory;
import model.Book;
public class BookFactory {
public Book createJavaBook(){
Book b = new Book();
b.setId("001");
b.setName("Thinking in java");
b.setAuthor("Bruce Eckel");
b.setPrice(12.3f);
return b;
}
}


则可以这样配置一个Book bean;
<bean id="bookFactory" class="model.factory.BookFactory" />
<bean id="myBook2" factory-bean="bookFactory" factory-method="createJavaBook" />


当然如果工厂方法是静态的, 则配置更简单,不过稍微有点玄乎.

先为BookFactory添加一个静态方法:
package model.factory;
import model.Book;
public class BookFactory {
public Book createJavaBook(){
Book b = new Book();
b.setId("001");
b.setName("Thinking in java");
b.setAuthor("Bruce Eckel");
b.setPrice(12.3f);
return b;
}

public static Book create(){
return new Book("www","www","www", 0.0f);
}
}


配置book bean:
<bean id="myBook3" class="model.factory.BookFactory" factory-method="create" />,
这个bean得到的是Book对象而不是BookFactory.

自动装配: 即对某bean的属性可以交给容器自己去匹配, 自动装配autowire可以取"byType", 或"byName";

注解注入: 3.0以后可以启用注解, 让容器自己扫描指定包下面的组件, 并把组件装配起来, 支持的注解有@Component, @Repository, @Service, @Controller, @Aurowired...

bean的依赖关系: spring的最重要的概念之一: 依赖注入, 所以bean的配置中一定要体现这种特性,一个类A使用了另一个类B, 则A依赖于B,比如有类Person,依赖于Date.

package model;

import java.util.Date;

public class Person {
private String name;
private char sex;
private Date birthday;

public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}

public String toString(){
return "name: " + name + "/nsex: " + sex + "/nbirthday: " + birthday.toLocaleString();
}
}
则配置:
<bean id="dt" class="java.util.Date"></bean>
<bean id="person" class="model.Person">
<property name="name" value="sunxing007" />
<property name="sex" value="M" />
<property name="birthday" ref="dt" />
</bean>

ref的意思就是参考到另一个bean.

集合的注入:比如有class:
JavaBookStore
package model;
import java.util.*;
public class JavaBookStore {
//普通书
private List commonBooks;
//畅销书
private Set favorites;
//出版商简称和全名的映射
private Map publisherMappings;

public List getCommonBooks() {
return commonBooks;
}

public void setCommonBooks(List commonBooks) {
this.commonBooks = commonBooks;
}

public Set getFavorites() {
return favorites;
}

public void setFavorites(Set favorites) {
this.favorites = favorites;
}

public Map getPublisherMappings() {
return publisherMappings;
}

public void setPublisherMappings(Map publisherMappings) {
this.publisherMappings = publisherMappings;
}
}


则配置如下:
<bean id="javaBookStore" class="model.JavaBookStore" >
<property name="commonBooks">
<list>
<ref bean="myBook1" />
<ref bean="myBook2" />
<ref bean="myBook3" />
</list>
</property>
<property name="favorites">
<set>
<ref bean="myBook1" />
<ref bean="myBook2" />
<ref bean="myBook3" />
</set>
</property>
<property name="publisherMappings">
<map>
<entry key="phei" value="Publishing House of Electronics Industry" />
<entry key="cmp" value="China machine Press" />
<entry key="ptp" value="Post and TeleCOM Press" />
<entry key-ref="myBook1" value-ref="myBook1" />
</map>
</property>
</bean>


其中myBook1,myBook2,myBook3是前面我们注入的几个Book bean.
bean的作用域: bean有五种作用域:
singleton, prototype, request, session, globalSession,其中后3种在WebApplicationContext下才有效. 默认的作用域是singleton;

来看<bean id="dt" class="java.util.Date"></bean>; 测试代码:
ApplicationContext c = new ClassPathXmlApplicationContext("spring-test.xml");
Date now = (Date)c.getBean("dt");
System.out.println(now.toLocalString());
Thread.sleep(1000);
now = (Date)c.getBean("dt");
System.out.println(now.toLocalString());


则两次打印出来的时间是一样的,因为默认的作用域是singleton, 相当于

<bean id="dt" class="java.util.Date" scope="singleton"></bean>,因为singleton只会实例化一次;

如果改成<bean id="dt" class="java.util.Date" scope="prototype"></bean>,则两次结果不一样.

singleton的bean还可以指定lazy-init属性,
<bean id="dt" class="java.util.Date" lazy-init="true"></bean>,表示只有用到的时候才实例化.

关于bean的注入还有两个比较有趣的地方.可能用到的地方会比较少,但是我在项目中的确用到过.

方法注入:考虑到从一个singleton的bean能够每次都返回一个prototype的bean, 因为作用域的原因,依靠我们以前的配置无法做到,但是方法注入可以。方法注入就是通过注入的方式替换方法返回的结果。看一个接口:
package model;

import java.util.Date;
public interface TimeReporter {
public Date getDate();
}


配置文件:
<bean id="dt" class="java.util.Date" scope="prototype"></bean>
<bean id="reporter" class="model.TimeReporter">
<lookup-method name="getDate" bean="dt" />
</bean>


测试代码:
ApplicationContext c = new ClassPathXmlApplicationContext("spring-test.xml");
while(true){
Thread.sleep(1000);
TimeReporter b = (TimeReporter)c.getBean("reporter");
System.out.println(b.getDate().getTime());
}


虽然TimeReporter没有方法体, 但是通过方法注入,相当于给getDate动态添加了实现。不过要把CGLib包加入到classpath。

继承:考虑到如果有几个book他们大多数属性的value都是一样的,只是有个别属性不一样,比如书的颜色, 则可以配置一个abstract的bean, 让其他的bean来继承它, 而其他的bean只需要配置少量的属性就可以了。虽然下面的例子没有现实意义,不过将就一下,不耽误理解。他们的name, author, price都一样, 只是编号不一样。
<bean id="absBook" class="model.Book" abstract="true">
<property name="name" value="Thinking in java" />
<property name="author" value="Bruce Eckel" />
<property name="price" value="2222" />
</bean>
<bean id="myBook4" class="model.Book" parent="absBook">
<property name="id" value="000002" />
</bean>
<bean id="myBook5" class="model.Book">
<property name="id" value="000003" />
</bean>


 

Spring的配置很灵活,不可能面面俱到,更多的内容需要在实际项目中体会。

下一讲将学习spring容器的高级特性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐