从本质上来看Spring容器就是一个超级大工厂,Bean就是工厂的产品,能产生哪些产品是根据我们配置文件的配置来的。对于我们开发者来说,使用Spring容器主要做两件事:1,定义自己的Bean,2配置Bean。对于Spring框架来说,它的作用就是根据配置文件创建Bean,并调用Bean的实例方法完成依赖注入——这就是所谓Ioc容器的本质。
其实Spring框架的本质就是通过XML配置来驱动Java代码,这样把原本有Java代码管理的组件之间的耦合关系,提取到了XML中。这样就方便了日后的升级和维护。
元素是Spring容器的根元素,该元素可以指定如下属性:
default-lazy-init:指定该元素下配置的所有默认的延迟行为。
default-merge:指定该元素下配置的所有默认的merge。
default-autowirt:指定该元素下配置的所有默认的自动装配行为。
default-autowirt-candidates:指定该元素下所有默认是否是默认装配的候选Bean。
default-init-method:指定该元素下所有默认的初始化方法。
default-destroy-method:指定该元素下所有默认的回收方法。
以上这些属性也使用于元素,只不过是需要去掉default而已。如果和配置了相同的属性,那么属性将会覆盖属性,也就说说一个相当于全局变量,一个想定于局部变量。
当通过Spring容器创建Bean时,不仅可以完成Bean的初始化工作,还可以为Bean指定作用域。在Bean元素添加scope属性即可配置Bean的作用域。Spring支持一下五种作用域:
1. singleton:单例模式,在整个Spring Ioc容器中,singleton作用域的Bean只会产生一个实例。
2. prototype:通过getBean()方法获取Bean实例或向其他Bean注入Bean时,Spring Ioc容器都会新new一个Bean实例作为方法返回的Bean或注入的Bean实例。
3. request:对于一次HTTP请求,request作用域只产生一个Bean实例,请求结束时Bean实例将会销毁。也就说两次login请求,将会产生两个userBean。每一次login请求多次调用userBean会得到同一个实例。只有在Web应用中使用Spring时,该作用域才有效。
4. session:对于一次HTTP会话,session作用域只产生一个Bean实例,session销毁时Bean实例将会销毁。也就是说用户A和用户B都请求了查询操作,将会产生两个queryBean实例。A用户多个请求查询操作,将会产生一个queryBean实例。只有在Web应用中使用Spring时,该作用域才有效。
5. global session:每个全局的HTTP session对应一个bean实例。在典型的情况下,仅在使用porlet context的时候才有效。只有在Web应用中使用Spring时,该作用域才有效。(可以了理解成jsp的application内置对象作用范围)
比较常用的是singleton和prototype作用域。对于singleton作用域的Bean,每次通过id获取Bean都是同一个实例,由Spring负责跟踪Bean的状态,维护Bean声明周期内的行为。对于prototype作用域的Bean,每个通过id获取Bean都是一个新的Bean实例,Spring会通过new关键字创建这个Bean实例,Spring不负责管理维护Bean实例的状态和行为。如果元素不指定scope属性将会默认为singleton作用域。prototype作用域会增加系统的开销,因为每次都需要创建一个对象(申请内存、销毁实例、完成垃圾回收等工作)。singleton作用域的Bean一旦创建成功,就可以重复使用。因此,应该尽量避免使用prototype作用域。
Bean的依赖注入通常有两种形式:
设值注入:通过元素驱动Spring容器调用setter方法来注入依赖的Bean。
构造注入:通过元素驱动Spring容器调用有参数(参数数元素配置)的构造函数。
BeanFactory和ApplicationContext容器实例化Bean的时机不同:前者是在需要Bean实例时,才会创建Bean。后者是在容器创建ApplicationContext实例时会预先初始化素有的singleton Bean。这样的做法会在启动Spring容器时增加系统的开销,但是一旦创建了所有的singleton Bean,后续获取Bean的相应会更快。BeanFactory不会在Spring容器启时实例化Bean,如果Spring Bean 配置文件有错误,会延迟到获取Bean时才会抛出,这也给系统带来了不安全因素。如果我们没有特殊需要,一般Java EE程序都会使用ApplicationContext作为Spring容器。总的来说:
1,BeanFactory和ApplicationFactory实例化Bean的机制不同。
2,一个是按需创建Bean,一个是启动时创建所有singleton Bean。
3,如果Bean配置有错误,一个是在实例化时才会发现,一个是容器启动时就会发现。
不是两种注入方式中的那种注入,都需要为参数传递参数值。可以传递参数的类型就是java类中成员变量可以定义的类型。也就时我们可以通过两种注入方法注入Bean实例、注入基本类型、数字、字符串、List和Map。所以Spring允许通过以下元素为这两种注入方法指定参数值:value、ref、bean、list、set、map和props。稍后会对每个元素进行详细说明。
元素用于指定基本类型以及包装类、String类型的参数值。Spring解析XML中配置的value,然后利用java.beans.PropertyEditor完成类型转账:从String类型转换成对应的参数类型值。元素配置方法如下:
假设Person有个setColor(String color)方法。
id="person" class="com.ssh.zxy.chapter7_2_2.Person">
<property name="color" value="黄色">property>
也可以这样配置:
<bean id="person" class="com.ssh.zxy.chapter7_2_2.Person">
<property name="color">
<value>黄色value>
property>
bean>
这两种配置目的是一样的,只不过是写法不同而已。前者配置更简洁,后者配置想的臃肿。同理也可这这样配置value属性,来为构造器注入字面量。
将一个Bean注入到容器的其它Bean实例中,可以使用元素来完成。这里就没有什么好说的了。配置如下:
id="person" class="com.ssh.zxy.chapter7_2_2.Person">
<property name="axe" ref="axe">property>
id="axe" class="com.ssh.zxy.chapter7_2_2.Axe">
Spring能自动装配Bean与Bean之间的依赖关系,即无需使用ref显示的指定依赖的Bean的Id,而是由Spring容器自动查找XML配置文件内容,根据某种规则自动注入符合规则的Bean。
自动装配可以降低XML配置的工作量,但是也降低了依赖关系的透明度和清晰性(我们还需要理解规则,然后肉眼去找符合规则Bean,想想就麻烦)。
autowire、default-autowire属性可以接受如下值:
no:不适用自动装配。Bean必须通过ref属性来定义依赖的bean。
byName:根据setter方法名进行匹配。Spring容器会查找配置内容中Bean ID名称符合setter方法名称去掉set,首字母变成小写的。如果找到就注入调用Bean中。如果没找到匹配的Bean就不进行任何注入。
byType:根据类型进行匹配。Spring容器会查找配置内容中Bean类型与setter方法参数类型相同的就进行注入。如果找到多个将会抛出异常。如果没找到Bean就不会进行注入。byName是setter方法名与Bean id匹配的策略。byType是settter方法参数类型与Bean类型匹配的策略。