Spring IOC--Bean的装配

来源:互联网 发布:linux终端运行w3m 编辑:程序博客网 时间:2024/04/28 14:42

IOC概述

Spring IOC被称之为控制反转(Inverse of Control),即将对象的创建控制权交给容器来控制,又有人将其称之为依赖注入。主要用来解耦各个对象之间的依赖关系,把依赖对象的创建及维护都放在Spring的IOC容器中。IOC是Spring的核心功能,很多其他功能,如:AOP、声明事务等都是在IOC的基础上实现的。其底层是通过java的反射技术来实现依赖对象的注入。

Spring中的Bean

spring根据提供的Bean配置信息来启动运行,Bean配置信息定义了Bean的实现及依赖关系,Spring容器根据各种形式的Bean配置信息在容器内部建立Bean定义注册表,然后根据Bean定义注册表加载、实例化Bean,并建立Bean和Bean的依赖关系。最后将这些创建好的Bean实例放入Bean实例缓存池中,供应用下次使用。

Bean的基本配置:

在Spring中配置Bean可以有多种形式,可以通过xml配置<bean>,也可以使用注解来配置bean。在使用注解时需要配置spring扫描的package,使用<context:component-scan  base-package="cn.qing.spring"/>进行指定。

xml配置bean:
下面展示一个最基本的vo bean在spring中的配置。
vo对象PersonInfo.java:
package cn.qing.spring.bean;public class PersonInfo {private String name;private int age;private String addr; public void initMethod(){System.out.println("init personInfo ....");}public void destoryMethod(){System.out.println("destory personInfo...");}@Overridepublic String toString() {return "PersonInfo [name=" + name + ", age=" + age + ", addr=" + addr+ "]";}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 String getAddr() {return addr;}public void setAddr(String addr) {this.addr = addr;}}

spring配置文件:applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsdhttp://www.springframework.org/schema/context    http://www.springframework.org/schema/context/spring-context-3.2.xsd">    <!-- 在使用注解时,在此配置spring要扫描加载的bean的base package -->    <context:component-scan base-package="cn.qing.spring"/>    <!-- 配置PersonInfo Bean,并填充其属性值 -->    <bean id="personInfo" class="cn.qing.spring.bean.PersonInfo" init-method="initMethod"       destroy-method="destoryMethod" scope="singleton" >    <property name="name" value="qing"/>    <property name="age" value="20"/>    <property name="addr" value="addr"/>    </bean></beans>

看一下spring的配置文件,<beans></beans>作为spring配置文件的根标签,spring中的其他各个组建都是在这个根标签下申明的,如:bean、aop、事务、spring的mvc配置等,都包含在<beans>下,在beans申明时指定了多个Schema,我们在使用到某些功能时需要应用的配置上对应的xml schema,如在使用aop时,我们必须引入
xmlns:aop="http://www.springframework.org/schema/aop"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
配置bean:
<bean id="personInfo" class="cn.qing.spring.bean.PersonInfo" init-method="initMethod"     <span style="white-space:pre"></span>  destroy-method="destoryMethod" scope="singleton" >
一般情况下在配置一个<bean>时需要为其指定一个id属性作为Bean的名称,id的值在IOC容器中必须是唯一的,我们也可以是使用name属性为bean指定名称,name属性并没有唯一要求,如果出现名称相同的情况,在通过getBean(String name)时会将前面申明的name对应的bean给覆盖掉,返回最后一个申明的bean。这有时应该不是我们希望的,所以一般在申明bean时都是指定id属性用来标识bean.
class属性用于指定bean类的全路径,init-method用来申明初始化bean时要做的准备工作,destroy-method申明在销毁bean时执行的方法,scope的值有多个:singleton、prototype、request、session。当设置为singleton时表示该bean被申明为一个单利模式,一旦被IOC容器创建以后就会放入Bean实例的缓冲池中,下次再通过getBean方法获取该bean时是从缓存中拿到的bean,可以从下面的测试类的输出中看到结果。当设置为prototype时,表示该bean每次在使用时都会由IOC容器创建一个新的bean实例,而且该实例不会放入bean缓存池中。对于request和session是在web应用时指定该bean的作用范围是request或session的。如果不指定bean的scope,默认为singleton。

测试类:
package cn.qing.spring.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.qing.spring.bean.PersonInfo;public class TestSpringBean {public static void main(String[] args) {//获取ApplicationContextApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//使用getBean方法得到以申明在配置文件中的beanPersonInfo info = (PersonInfo)context.getBean("personInfo");System.out.println(info.toString());//由于personInfo的scope申明为singleton再次获取bean是从IOC缓存中获取PersonInfo info2 = (PersonInfo)context.getBean("personInfo");System.out.println("info == info2 ? result is :"+(info==info2));}}

输出结果:
init personInfo ....PersonInfo [name=qing, age=20, addr=addr]info == info2 ? result is :true

上面的例子是使用spring最简单的bean配置及获取并实例化Bean。我们可以看到,在配置bean的时候就为personInfo注入了属性值,所以我们在获取personInfo对象后通过toString方法可以打印出各个属性的值,这种注入的方式属于属性注入。

注入方式:

spring支持两种注入方式:属性注入和构造函数注入,除此之外还有一种工厂注入方式。

属性注入:

属性注入即通过setXxx()方法注入bean的属性值或依赖对象,由于属性注入具有可选择性和灵活性高的优点,所有在大多数情况下,我们都是采用属性注入的方式。属性注入要求Bean提供一个默认的构造方法,并为bean的属性提供setXxx()方法,Spring在实例化bean时,先调用bean的默认构造方法创建bean,然后在通过反射方式调用setXxx()注入属性值。
<property name="name" value="qing"/><property name="age" value="20"/><property name="addr" value="addr"/>
在前面的PersonInfo.java类中,我们就为该类编写了3个属性字段,同时为其提供了setXxx()和getXxx()方法,在配置<bean>时为这3个字段通过<property name="name" value="qing"/>标签注入属性值,<property>的name指定属性的名称,在bean中应该拥有一个与其对应的setXxx()方法,其实spring在进行属性注入的时候只是会检测有没有与name对应的setXxx()方法,而不会要求bean中有对应的name属性,但是在一般情况下,我们还是使用约定俗成的方式为bean指定属性并提供对应的setXxx()和getXxx()方法。<property>标签还有一个常用属性:ref属性。这个属性是为了注入其他声明的bean对象,且这个bean对象是以属性声明在使用它的bean中,这就是我们最常用到的bean的依赖注入,来达到各个类之间的解耦。
<!-- 配置PersonInfo Bean,并填充其属性值 -->    <bean id="personInfo" class="cn.qing.spring.bean.PersonInfo" init-method="initMethod"       destroy-method="destoryMethod" scope="singleton" >    <property name="name" value="qing"/>    <property name="age" value="20"/>    <property name="addr" value="addr"/>    <property name="other" ref="other"/>    </bean>    <!-- 另一个Bean对象 -->    <bean id="other" class="cn.qing.spring.bean.OtherBean"/>
通过这种方式注入other对象以后,我们就可以在personInfo实例中直接使用other对象,并不需要实例化,当然,这个other对象在personInfo中也需要申明对应的setXxx()方法。

关于属性命名的特殊规范:

一般情况下java的属性命名都是以小写开头,如:stuName、sutAge等,但是也存在特殊的情况,考虑到会有一些大写英文缩略词如:USA、XML等,javaBean也允许大写字母起头的属性,但是必需满足变量的前两个字母要么全大写,要么全部小写,如:name、IDCode等这些都是合法的,而IdCard、IdCode、iDCode等这些只有第一个字母为大写的情况是非法的,这会引发一些在配置上使人困惑的错误情况发生,因为setXxx()方法会默认将变量的第一个字母大写,如iDcode为setIDCode(),在配置
<property name="iDCode" value="123"/>
之后,spring启动会出现错误的提示,说没有为iDCode提供对应的setter方法,这就是我们定义了一个非法的属性名导致的,这些是在我们开发命名对象的属性名时需要注意的地方:变量的前两个字母要么全大写,要么全部小写。

构造函数注入:

构造函数注入是属性注入方式之外的另一种注入,它保证一些必要的属性在实例化时就得到设置,保证了实例在实例化后就可以使用。spring在通过构造函数进行注入时有多种匹配方式。
一个包含构造函数的简单bean
package cn.qing.spring.bean;public class ConstructorBean {private String name;private int age;private String sex;public ConstructorBean(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;System.out.println("input Constructor method...");}@Overridepublic String toString() {return "ConstructorBean [name=" + name + ", age=" + age + ", sex="+ sex + "]";}}
按类型匹配:
<!-- 使用构造函数进行注入 --><bean id="const" class="cn.qing.spring.bean.ConstructorBean"><!-- 匹配String类型的属性 --><constructor-arg type="java.lang.String" value="const_name"/><!-- 匹配int类型的属性 --><constructor-arg type="int" value="22"/><constructor-arg type="java.lang.String" value="man"/></bean>

//获取ApplicationContextApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");ConstructorBean cb = (ConstructorBean)context.getBean("const");System.out.println(cb.toString());
输出结果:
input Constructor method...ConstructorBean [name=const_name, age=22, sex=man]
可以看到,通过构造函数可以成功将属性注入到bean中。

按索引匹配:
<!-- 使用构造函数进行注入 --><bean id="const" class="cn.qing.spring.bean.ConstructorBean"><!-- 匹配第一个索引对应的属性 --><constructor-arg index="0" value="const_name"/><!-- 匹配第二个索引对应的属性 --><constructor-arg index="1" value="22"/><constructor-arg index="2" value="man"/></bean>

按类型和索引集合匹配:
<!-- 使用构造函数进行注入 --><bean id="const" class="cn.qing.spring.bean.ConstructorBean"><!-- 匹配第一个索引,类型为String对应的属性 --><constructor-arg index="0" type="java.lang.String" value="const_name"/><!-- 匹配第二个索引,类型为int对应的属性 --><constructor-arg index="1" type="int" value="22"/><constructor-arg index="2" type="java.lang.String" value="man"/></bean>

以上这几种方式都可以正常的通过构造函数注入,另外,<constructor-arg>标签也有一个ref属性,这个属性和<property>的ref作用和用法一样,在此不进行举例。




0 0
原创粉丝点击