内容参考自spring in action一书。
创建应用对象之间协作关系的行为通常称为装配,这也是依赖注入的本质。
1. 创建spring配置
spring是一个基于容器的框架。如果没有配置spring,那么它就是一个空的容器,所以需要配置spring来告诉容器它需要加载哪些Bean和如何装配这些bean,这样才能确保它们能够彼此协作。
从spring3.0开始,spring容器提供了两种配置bean的方式。第一种是传统上的使用一个或多个XML文件作为配置文件。第二种提供了基于java注解的配置方式。
先说XML文件的配置方式:
在XML文件中声明Bean时,Spring配置文件的根元素是来源于Spring Beans命名空间所定义的<beans>元素。下面是一个典型的Spring XML配置文件。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Bean declarations go here --> </beans>
在<beans>元素内可以放置所有的Spring配置信息,包括<bean>元素的声明。但是beans的命名空间并不是唯一的Spring命名空间。Spring的核心框架自带了10个命名空间配置。如下所示:
2. 注入bean属性
spring注入bean属性有三种方式,常用的有两种,第一种是通过构造器注入。第二种是通过Setter注入。
第一种,通过构造器注入:
先看最简单的构造器注入方式,通过默认构造函数进行注入。
<bean id="duke" class="com.pcitc.springInAction.Juggler" />
通过构造器注入简单值:
现在进行按需实例化,不走默认的构造方法:
<bean id="duke" class="com.pcitc.springInAction.Juggler"> <constructor-arg value="15" /> </bean>
总结:在构造bean的时候可以使用 <constructor-arg>元素来告诉spring额外的信息。如果不配置 <constructor-arg>元素,那么spring将使用默认的构造方法,上面配置了 <constructor-arg>的value属性设置为15,Spring将调用Juggler的另一个构造方法。
通过构造器注入对象引用:
<bean id="sonnet29" class="com.pcitc.springInAction.Sonnet29" /> <bean id="poeticDuke" class="com.pcitc.springInAction.PoeticJuggler"> <constructor-arg value="15" /> <constructor-arg ref="sonnet29" /> </bean>
总结: <constructor-arg ref="sonnet29" />,把bean引用传递给构造器,当spring碰到sonnet29和duke的声明时,它所执行的逻辑本质上和下面的java代码相同:
Poem sonnet29 = new Sonnet29(); Performer duke = new PoeticJuggler(15, sonnet29);
通过工厂方法创建Bean:
假如想声明的Bean没有一个公开的构造方法,那怎么办呢?方法是通过工厂方法创建bean。
有时候静态工厂方法是实例化对象的唯一方法。Spring支持通过<bean>元素的factory-method属性来装配工厂创建的bean。
定义一个单例类:
package com.pcitc.springInAction; public class Stage { private Stage() { } private static class StageSingletonHolder { static Stage instance = new Stage(); } public static Stage getInstance() { return StageSingletonHolder.instance; } }
Stage类没有一个公开的构造方法,这时候只能通过Spring的factory-method属性调用一个指定的静态方法,从而代替构造方法来创建一个类的实例。
在Spring配置文件下这样来声明该bean
<bean id="theStage" class="com.pcitc.springInAction.Stage" factory-method="getInstance" />
第一种,通过Setter方法注入:
通常javabean的属性都是私有的,同时拥有一组存取器方法,以setXXX和getXXX形式存在.spring可以借助属性的set方法来配置属性的值,以实现setter方法注入。
简单说明:
注入简单值的方式:
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist"> <property name="song" value="Jingle Bells" /> </bean>
在spring配置文件中,一旦Instrumentalist被实例化,<peoperty>元素会指示Spring调用setSong方法将song属性的值设置为"Jingle Bells"。需要说明的是value值的类型不基于String类型,也可以是数值类型和boolean类型,spring会根据属性值的类型进行自动转换。
通过Setter注入对象引用:
<bean id="kenny2" class="com.springinaction.springidol.Instrumentalist"> <property name="song" value="Jingle Bells" /> <property name="instrument" ref="saxophone" /> </bean>
注入内部bean:
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist"> <property name="song" value="Jingle Bells" /> <property name="instrument"> <bean class="org.springinaction.springidol.Saxophone" /> </property> </bean>
内部bean是通过直接声明一个<bean>元素作为<property>元素的子节点而定义的,内部bean并限于setter注入,还可以把内部bean装配到构造方法的入参中,如下所示:
<bean id="duke" class="com.springinaction.springidol.PoeticJuggler"> <constructor-arg value="15" /> <constructor-arg> <bean class="com.springinaction.springidol.Sonnet29" /> </constructor-arg> </bean>
在这里,Sonnet29的一个实例将作为内部bean被创建,并作为参数传递给PoeticJuggler的构造器。
总结:需要注意的是内部Bean没有ID属性。虽然为内部bean配置一个ID属性是合法的,但是完全没有必要,因为永远不会通过名字来引用内部bean。这也突出了使用内部bean的最大缺点:它们不能被复用。内部bean仅适用于一次注入,而且也不能被其他bean所引用,而且某种程度上还会影响Spring XML配置的可读性。