标签:
Spring 利用 Ioc 容器管理 Bean,前提是 Bean 需要在配置文件声明(定义)。
声明一个 Bean 需要的基本元素如下:
元素 | 作用 |
---|---|
class | 全限定类名,即 Bean 的完整包名,是必不可少的元素。 |
id | 标识,在整个 Ioc 容器中必须唯一,用来区分不同的 Bean。若 Bean 未指定 id,则 Ioc 容器会为其自动生成一个标识;只能配置一个。 |
name | 标识符或名称, 作用与别名一致;在整个 Ioc 容器汇总必须唯一,但是可以配置多个。 |
alias | 别名,在整个 Ioc 容器汇总必须唯一,但是可以配置多个。 |
声明一个 Bean 的配置如下:
<!-- 1.只配置必须的全限定类名(class),由Ioc 容器为其生成一个标识 -->
<bean class="com.demo.Animals"/>
<!-- 2.指定 id,该标识在 Ioc 容器中必须唯一 -->
<bean id="animals" class="com.demo.Animals"/>
<!-- 3.指定 name,该标识在 Ioc 容器中必须唯一,同一个 Bean 中 name 可以相同 -->
<!-- 可配置一个或多个,第一个会被当作标识,其余的被当作别名 -->
<bean name="animals,Animals" class="com.demo.Animals"/>
<!-- 4.同时指定 id 和 name -->
<bean id="animals" name="animals" class="com.demo.Animals"/>
<!-- 5.同时指定 id 和 alias -->
<!-- alias 在 Bean 中不能单独存在,必须指定 id 或 name -->
<!-- alias 可配置一个或多个,标识在整个 Ioc 容器唯一,在 Bean 中可以 相同 -->
<!-- alias 元素的 name 表示 Bean 的 id 或 name -->
<bean id="animals" class="com.demo.Animals"/>
<alias name="animals" alias="a"/>
<alias name="animals" alias="b"/>
<!-- 6.同时指定 name 和 alias -->
<bean name="animals" class="com.demo.Animals"/>
<alias name="animals" alias="a"/>
<alias name="animals" alias="a"/>
注意事项:
id 在同一个 Bean 中只能指定一个,name 和 alias 可以指定多个;
同时存在 id 和 name 时,id 作为标识,name 会被当作别名;
存在多个 name 时,第一个 name 会被当作 标识,其余的 name 会被当作别名;
多个 name 或 alias 之间可以用分号(;)、空格、逗号(,)隔开。
在 Spring Ioc 容器声明了 Bean 之后,就表示将 Bean 交给 Spring 去管理,由 Spring 负责 Bean 的整个生命周期,包括 Bean 的创建、销毁等等。
这就是所谓的控制反转(Ioc),将 Bean 的控制权交给 Spring,我们无需常见它,只需调用它即可。
通过 Spring Ioc 容器调用 Bean 的方式有三种:根据类型、根据名称、根据名称+类型。
注意事项:
若 Ioc 容器中存在多个同一类型的 Bean 时,根据类型取得 Bean 时会抛出 NoUniqueBeanDefinitionException 异常
若找不到指定名称或类型的 Bean时,会抛出 NoSuchBeanDefinitionException 异常
// 配置文件路径
String path = "/WebRoot/WEB-INF/spring-bean.xml";
// 取得 Spring 的 Ioc 容器(也称应用上下文)
ApplicationContext context = new FileSystemXmlApplicationContext(path);
// 由 Ioc 容器获取定义的 Bean:
// ①根据 Bean 的类型(容器存在多个相同类型 Bean,抛出异常)
Animals animal = (Animals) context.getBean(Animals.class);
// ②根据 Bean 的名称Animals animal = (Animals) context.getBean("animals");
// ③根据 Bean 的类型和名称
Animals animal = (Animals) context.getBean("Animals",Animals.class);
观察上面的代码,发现在没有创建的 Bean(即创建实例,如 new)情况下,实现了对 Bean 的调用。
实际上是在创建 Ioc 容器时,它已经利用反射通过 Bean 的无参构造函数完成了 Bean 的实例化,所以才可以直接调用。
Bean 的注入,也称依赖注入,其实它包含了两个部分:依赖和注入。
// ① 对于类 Animals 来说,此时依赖就是它的构造参数:name。
public class Animals {
public Animals(String name){
//do something...
}
}
// ② 对于类 Animals 来说,此时依赖是它的成员变量:Cat 类。
public class Animals {
private Cat cat;
//省略 sertter/getter...
}
// ③ 对于类 Animals 来说,此时没有依赖关系,也就没所谓的注入。
public class Animals {
}
在 Spring 中注入方式有四种:构造器注入、setter 注入、静态工厂注入、实例工厂注入。
首先来看在未使用 Spring 之前是如何通过构造函数实例化一个类。
public class Animals {
public Animals(String name){
//...
}
public static void main(String [ ] args) {
String name ="dog";
Animals a = new Animals(name);
}
}
通过 Spring 的构造器注入构造参数并实例化它
<!-- <constructor-arg> 标签代表:构造函数的参数,共有 3 种方式可以指定参数值 -->
<!-- ①通过参数名称 -->
<bean id="animals" class="com.demo.Animals" >
<constructor-arg name="name" value="dog"/>
</bean>
<!-- ②通过参数序列号 -->
<bean id="animals" class="com.demo.Animals" >
<constructor-arg index="0" value="dog"/>
</bean>
<!-- ③通过参数类型 -->
<bean id="animals" class="com.demo.Animals" >
<constructor-arg type="java.lang.String" value="dog"/>
</bean>
String path = "/WebRoot/WEB-INF/spring-bean.xml";
ApplicationContext context = new FileSystemXmlApplicationContext(path);
首先来看在未使用 Spring 之前是如何通过 setter 方法指定成员变量并调用它
public class Animals {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String [ ] args) {
Animals a = new Animals();
a.setName("dog");
System.out.println(a.getName());
}
}
通过 Spring 的 setter 注入指定成员变量的值
<!-- <property> 标签代表 Bean 的成员变量 -->
<bean id="animals" class="com.demo.Animals" >
<property name="name" value="dog"/>
</bean>
ApplicationContext context = ...
Animals a = (Animals) context.getBean(Animals.class);
System.out.println(a.getName());
静态工厂指的是简单工厂模式,因为其创建实例的方法是静态方法,因此也称静态工厂模式。
下面来看如何通过静态工厂模式创建一个类。
// 产品类:Animals
public class Animals {
public Animals(String name) {
System.out.println("Creating Animal,Name is "+name);
}
}
// 静态工厂类:AnimalsFactory
public class AnimalsFactory {
public static Animals newInstance() {
return new Animals();
}
public static void main(String [ ] args) {
Animals a = AnimalsFactory .newInstance();
}
}
通过 Spring 的 静态工厂注入创建具体的产品类
<!-- factory-method 代码该 Bean 的静态工厂方法 -->
<!-- constructor-arg 表示通过静态工厂方法传递给产品类的构造参数 -->
<bean id ="animalsFactory" class="com.demo.AnimalsFactory" factory-method="newInstance">
<constructor-arg name="name" value="dog"/>
</bean>
// 此时已经完成 Animals 类的实例化
ApplicationContext context = ...
// 调用,注意 -> getBean 的参数
Animals a = context.getBean("animalsFactory",Animals.class);
同样是上面的例子,这里修改下工厂类。利用实例工厂类创建产品类。
public class AnimalsFactory {
public Animals newInstance(String name) {
return new Animals(name);
}
public static void main(String [ ] args) {
AnimalsFactory af = new AnimalsFactory();
Animals a = af.newInstance("dog");
}
}
通过 Spring 的 实例工厂注入创建具体的产品类。
<bean id="animalsFactory" class="com.demo.AnimalsFactory"/>
<bean factory-bean="animalsFactory" factory-method="newInstance">
<constructor-arg name="name" value="dog"/>
</bean>
上面介绍 Bean 注入方式时采用例子就是注入基本数据类型。
<bean id="animals" class="com.demo.Animals" >
<property name="name" value="dog"/>
</bean>
注意:
property 标签当中的 value,全部都是字符串类型,,由 Spring 容器将此字符串转换成属性所需要的类型,如果转换出错,将抛出相应的异常。
若 value 值是 boolean 类型,Spring 对其有容错处理,如用常见的(true/false)外,还可以使用(1/0)、(on/off)、(yes/no)表示。
若 value 值是为空,则利用 null 标签表示,如:
<bean id="animals" class="com.demo.Animals" >
<property name="name">
<null/>
<property >
</bean>
这里以 setter 注入为例,定义 Bean
public class Animals {
// 成员变量分别为 List,Set,Array 类型时
private List [Set] [Array] list;
//省略 setter/getter...
}
在 xml 文件中配置 Bean
<!-- ①成员变量的类型为 List -->
<bean id="animals" class="com.demo.Animals">
<property name="list">
<list>
<value>a</value>
<value>b</value>
</list>
</property>
</bean>
<!-- ②若成员变量的类型为 Set -->
<bean id="animals" class="com.demo.Animals">
<property name="list">
<set>
<value>a</value>
<value>b</value>
</set>
</property>
</bean>
<!-- ③若成员变量的类型为 Array -->
<bean id="animals" class="com.demo.Animals">
<property name="list">
<array>
<value>a</value>
<value>b</value>
</array>
</property>
</bean>
这里以构造器注入为例,定义 Bean
public class Animals {
public Animals(Map[Properties] map[prop]){
//do something...
}
}
在 xml 文件中配置 Bean
<!-- ①构造参数类型为 Map -->
<bean id="animals" class="com.demo.Animals" >
<constructor-arg name="map">
<map>
<entry key="a" value="1"/>
<entry key="b" value="2"/>
</map>
</constructor-arg>
</bean>
<!-- ①构造参数类型为 Properties -->
<bean id="animals" class="com.demo.Animals">
<constructor-arg name="prop">
<props>
<prop key="a" >1</prop>
<prop key="b" >2</prop>
</props>
</constructor-arg>
</bean>
引用其他Bean的步骤与注入基本数据类型的步骤一样,可以通过构造器注入及setter注入引用其他Bean,只是引用其他Bean的注入配置稍微变化了一下。
public class Cat{
}
public class Animals {
private Cat cat;
//省略 setter/getter...
public Animals(){
}
public Animals(Cat cat){
}
}
<!-- 被引用的 Bean -->
<bean id="cat" class="com.demo.Cat"></bean>
<!-- ①通过 setter 注入 -->
<bean id="animals" class="com.demo.Animals">
<property name="cat" ref="cat"/>
</bean>
<!-- ②通过构造器注入 -->
<bean id="animals" class="com.demo.Animals">
<constructor-arg name="cat" ref="cat"/>
</bean>
以上面的例子为例,内部定义 Bean 只需稍微修改下配置文件。
<!-- ①通过 setter 注入 -->
<bean id="animals" class="com.demo.Animals">
<property name="cat" >
<bean class="com.demo.Cat" />
</property>
</bean>
<!-- ②通过构造器注入 -->
<bean id="animals" class="com.demo.Animals">
<constructor-arg name="cat" >
<bean class="com.demo.Cat" />
</constructor-arg>
</bean>
注意:
当实例化一个 Bean 时,可能需要执行一个初始化操作来确保该 Bean 可用状态。同样地,当不需要 Bean 时,将其从容器中移除时,可能还需要按顺序执行一些清楚工作。
为 Bean 定义初始化和销毁操作,需要使用 init-method 和 destory-method 属性。
// 进入房间后要开灯,离开房间后要关灯
public class Room {
public Room(){
System.out.println("enter room...");
}
public void turnOnLights(){
System.out.println("turn on...");
}
public void turnOffLights(){
System.out.println("turn off...");
}
}
<bean class="com.demo.Room" init-method="turnOnLights" destroy-method="turnOffLights"/>
// 实例化 Bean
FileSystemXmlApplicationContext context = ...
// 销毁 Bean
context.registerShutdownHook();
// 输出内容:
// enter room...
// turn on...
// turn off...
标签:
原文地址:http://blog.csdn.net/u012420654/article/details/52464132