使用Spring的IoC容器
BeanFactory和ApplicationContext的介绍
BeanFactory介绍 BeanFactory是一个类工厂,但它和传统的类工厂不同,传统的类工厂仅生成一个类的对象,或几个实现某一相同接口类的对象。而BeanFactory是通用的工厂,他可以创建和管理各种类的对象。这些可被创建和管理的对象本身没有什么特别之处,仅是一个简单的POJO,Spring称这些被创建和被管理的Java对象为Bean。我们知道JavaBean是要满足一定规范的,如必须提供一个默认不带参的构造函数、不依赖于某一特定的容器等,但Spring中所说的Bean比JavaBean更宽泛一些,所以不需要额外服务支持的POJO都可以是Bean。
Spring为BeanFactory提供了多种实现,最常用的是XmlBeanFactory。我们该如何获得一个XmlBeanFactory呢?
代码清单1
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
或
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
代码清单1中我们通过FileSystemResource和ClassPathResource都获得了XmlBeanFactory。但是我们有了XmlBeanFactory对象又能干什么用呢?
代码清单2
public class Foo {
private String name;
public void setName(String name) {
this.name = name;
}
public String toStirng(){
return "Foo Name is :" + this.name;
}
}
xml version="1.0" encoding="UTF-8"?>
<beans xmlns="" xmlns:xsi="" xmlns:p="" xmlns:context="" xsi:schemaLocation="
[url][/url] [url]/spring-beans-2.5.xsd[/url]
[url][/url] [url]/spring-context-2.5.xsd[/url]">
<bean id="foo" class="com.tony.test.Foo">
<property name="name" value="Foo"/>
bean>
beans>
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class Test {
public static void main(String[] args) {
//定义Spring配置文件
ClassPathResource resource = new
ClassPathResource("spring-config-beans.xml");
//实例化BeanFactory
BeanFactory factory = new XmlBeanFactory(resource);
//根据配置文件中的id获得Bean
Foo foo = (Foo) factory.getBean("foo");
System.out.println(foo.toStirng());
}
}
运行结果 Foo Name is :Foo
代码清单2中我们首先定义了一个很普通的java类Foo.java然后在Spring配置文件中将其配置,关键的是我们的Test.java类我们首先实例化了ClassPathResource对象,在实例化时我们已经告诉了它Spring配置文件的名称,实例化BeanFactory后我们通过factory.getBean就可以获得由Spring管理的Bean了。我们惊奇的发现Spring竟然帮我们把Foo对象中name属性的数据装配进去了。
3.1.2 ApplicationContext 介绍 如果说BeanFactory是Spring的心脏,那么ApplicationContext就是Spring的五脏六腑和躯干四肢了。ApplicationContext接口由BeanFactory派生而来,提供了更多面向实际应用的功能,在BeanFactory中,很多功能需要以编程的方式进行操作,而在ApplicationContext中则可以通过配置的方式进行控制。简而言之,BeanFactory
提供了配制框架及基本功能,而ApplicationContext
则增加了更多支持企业核心内容的功能。ApplicationContext
完全由BeanFactory
扩展而来,因而BeanFactory
所具备的能力和行为也适用于ApplicationContext
。
3.2 Bean的基本配置
每个bean都有一个或多个id(或称之为标识符或名称,在术语上可以理 解成 一回事)。这些id在当前IoC容器中必须唯一。如果一个bean有多 个id, 那么其他的id在本质上将被认为是别名。
当使用基于XML的配置元数据时,将通过id
或name
属性来指定bean标识 符。 id
属性具有唯一性,而且是一个真正的XML ID属性,因此其他xml 元素在引用该id时,可以利用XML解析器的验证功能。通常情况下最好为 bean指定一个id。尽管XML规范规定了XML ID命名的有效字符,但是bean 标识符的定义不受该限制,因为除了使用指定的XML字符来作为id,还可以 为bean指定别名,要实现这一点可以在name
属性中使用逗号、冒号或者空 格将多个id分隔。
值得注意的是,为一个bean提供一个name并不是必须的,如果没有指定, 那么容器将为其生成一个惟一的name。
<bean id="foo" class="com.tony.test.Foo"/>
一般情况下,SpringIoC容器中的一个Bean即对应配置文件中的一个,这种镜像性的对应关系很容易理解。其中id为这个Bean的名称,通过容器的getBean(“foo”)即可获取对应的Bean,在容器中起到定位查找的作用,是外部程序和SpringIoC容器进行通信的桥梁。Class属性指定了Bean对应的实现类。
3.3 依赖注入
Spring支持两种依赖注入方式,分别是属性注入和构造函数注入。。
3.3.1属性注入
属性注入即通过setXxx()方法注入Bean的属性值或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入是实际应用中最常用的注入方式。
代码清单1
public class Foo {
private String name;
public void setName(String name) {
this.name = name;
}
public String toStirng(){
return "Foo Name is :" + this.name;
}
}
<bean id="foo" class="com.tony.test.Foo">
<property name="name" value="Foo"/>
bean>
Foo类中定义了一个属性name,并提供了对应的Setter方法,我们配置了一个Bean,并为该Bean的name属性提供了属性值。具体来说,Bean的每一个属性对应一个标签,name为属性的名称,在Bean实现类中拥有与其的对应的Setter方法name对应setName()方法。
3.3.2构造函数注入
构造函数注入是除属性注入之外的另一种常用注入方式,它保证一些必要的属性在Bean实例化时就得到设置,它保证了Bean实例在实例化后就可以使用。
代码清单1
public class Foo {
private String name;
private int age;
public Foo(String name,int age){
this.name = name;
this.age = age;
}
public String toStirng(){
return "Foo Name is :" + this.name;
}
}
<bean id="foo" class="com.tony.test.Foo">
<constructor-arg type="int">
<value>20value>
constructor-arg>
<constructor-arg type="java.lang.String">
<value>Foovalue>
constructor-arg>
bean>
代码清单1中我们定义了一个构造函数,接受一个String类型的入参,配置文件中我们配别通过元素中定义了type类型为java.lang.String和int的两个元素,Spring会通过type类型来对构造函数进行注入,因此我们在配置文件和构造函数入参顺序不同的情况下还是可以成功注入。但是我们对于多个构造函数并且类型都一样的时候我们改怎么办呢?
代码清单2
<bean id="foo" class="com.tony.test.Foo">
<constructor-arg index="0" value="Foo"/>
<constructor-arg index="1" value="20"/>
bean>
只要修改配置文件中元素把type属性改为index并且指定参数的索引就可一了,这里一定要注意索引是从0开始的。
3.4 Bean的作用域
在配置文件中定义Bean时,用户不单可以配置Bean的属性值以及相互之间的依赖关系,还可以定义Bean的作用域。作用域将对Bean的生命周期和创建方式产生影响。在低版本的Spring中,仅有两个作用域:singleton和prototype,在Spring2.0中,针对WebApplicationContext新增加了3个作用域。
singleton <bean id="foo" class="…" scope="singleton"/>
在SpringIoC容器中仅存在一个Bean实例,Bean以单实例的方式存在。
prototype <bean id="foo" class="…" scope="prototype"/>
每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean时,相当于执行newXxxBean的操作。
request <bean id="foo" class="…" scope="request"/>
每次HTTP请求都会创建一个新的Bean。该作用域仅适用于WebApplicationContext环境。
session <bean id="foo" class="…" scope="session"/>
同一个HTTPSession共享一个Bean,不同HTTPSession使用不同的Bean。该作用域仅适用于WebApplicationContext环境。
globalSession <bean id="foo" class="…" scope="globalSession"/>
同一个全局Session共享一个Bean,一般用于Protlet应用环境。该作用域仅适用于WebApplicationContext环境。