spring学习笔记:bean的配置
2009-08-10 15:05
471 查看
从Spring IOC容器中获取一个bean很简单,正如前面看到的,context.getBean("bean name");
关键是配置bean, 我们前面配置了一个叫做myBook的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指定了一个构造函数,像这样:
那么就可以这样来配置bean:
需要注意的是, 你给出的构造参数顺序要与构造函数一致.因为构造函数可以由多个.
工厂方法注入: 如果我们为Book提供一个工厂专门生产Book, 比如有这样一个非静态工厂:
则可以这样配置一个Book bean;
当然如果工厂方法是静态的, 则配置更简单,不过稍微有点玄乎.
先为BookFactory添加一个静态方法:
配置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.
ref的意思就是参考到另一个bean.
集合的注入:比如有class:
JavaBookStore
则配置如下:
其中myBook1,myBook2,myBook3是前面我们注入的几个Book bean.
bean的作用域: bean有五种作用域:
singleton, prototype, request, session, globalSession,其中后3种在WebApplicationContext下才有效. 默认的作用域是singleton;
来看<bean id="dt" class="java.util.Date"></bean>; 测试代码:
则两次打印出来的时间是一样的,因为默认的作用域是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, 因为作用域的原因,依靠我们以前的配置无法做到,但是方法注入可以。方法注入就是通过注入的方式替换方法返回的结果。看一个接口:
配置文件:
测试代码:
虽然TimeReporter没有方法体, 但是通过方法注入,相当于给getDate动态添加了实现。不过要把CGLib包加入到classpath。
继承:考虑到如果有几个book他们大多数属性的value都是一样的,只是有个别属性不一样,比如书的颜色, 则可以配置一个abstract的bean, 让其他的bean来继承它, 而其他的bean只需要配置少量的属性就可以了。虽然下面的例子没有现实意义,不过将就一下,不耽误理解。他们的name, author, price都一样, 只是编号不一样。
Spring的配置很灵活,不可能面面俱到,更多的内容需要在实际项目中体会。
下一讲将学习spring容器的高级特性。
关键是配置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容器的高级特性。
相关文章推荐
- Spring学习笔记 使用XML配置实现Bean的auto-wiring (自动绑定)
- Spring学习笔记之通过注解配置Bean(1)
- [原创]java WEB学习笔记99:Spring学习---Spring Bean配置:自动装配,配置bean之间的关系(继承/依赖),bean的作用域(singleton,prototype,web环境作用域),使用外部属性文件
- Java框架spring 学习笔记(十):bean管理(注解和配置文件混合使用)
- spring学习笔记十 通过factoryBean配置bean
- Spring学习笔记(二)Bean配置
- Spring学习笔记三: 通过注解配置Bean
- Spring学习笔记之配置bean的方式(工厂方法和Factorybean)
- [原创]java WEB学习笔记98:Spring学习---Spring Bean配置及相关细节:如何在配置bean,Spring容器(BeanFactory,ApplicationContext),如何获取bean,属性赋值(属性注入,构造器注入),配置bean细节(字面值,包含特殊字符,引用bean,null值,集合属性list map propert),util 和p 命名空间
- [原创]java WEB学习笔记100:Spring学习---Spring Bean配置:SpEL详细介绍及代码演示
- spring中Bean的xml方式配置学习笔记
- Spring学习笔记(2)——Bean的配置
- Spring4 学习笔记(3)-Spring 基于 XML 的方式配置 Bean(供自己学习)
- Spring4学习笔记-通过注解配置bean
- 【spring学习笔记一】使用xml文件配置bean
- Spring学习笔记三: 通过注解配置Bean
- [原创]java WEB学习笔记97:Spring学习---Spring 中的 Bean 配置:IOC 和 DI
- spring学习笔记整理--04(配置Spring管理的bean的作用域、生命周期)
- spring学习笔记(12)——使用注解方式配置bean
- [原创]java WEB学习笔记102:Spring学习---Spring Bean配置:bean配置方式(工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean) 全类名