1 bean定义
1.1 命名
给bean命名不是必须的,但是如果如果有其它bean需要引用该bean,那么就需要给该bean命名。当我们没有给bean命名时,Spring将自动为该bean生成一个唯一的名称。
1.1.1 id和name属性
可以通过id和name给bean命名,如果只需要给bean指定一个名称则使用id和name都可以。id和name在整个ApplicationContext
中都要求是唯一的,其中id我们只能指定一个,如果我们还需要为当前bean指定更多的名称,则可以通过name进行指定。name属性可以用来为bean指定多个名称,多个名称之间可以以逗号“,”、分号“;”或空格进行分隔。
<bean id="hello" name="hello2,hello3 hello4;hello5" class="java.lang.String">
<constructor-arg value="hello"/>
</bean>
1.1.2 alias元素指定别名
alias
元素可以为指定的名称指定一个别名。假设在我们的ApplicationContext
中拥有一个名为name1的bean,同时通过alias
元素指定了name1的别名为alias1,这样在其它需要引用名为name1的bean的地方都可以使用alias1来代替,当然继续使用name1也是可以的。这种机制是非常有效的。考虑这样一种场景,假设我们的应用有两个module,其中module1需要关联名为module1-dataSource,module2需要关联名为module2-dataSource。但实际上它们使用的都是同一个数据源,当然我们可在定义该DataSource时同时指定其名称为module1-dataSource和module2-dataSource。另一种方式是我们可以为该DataSource指定两个别名,分别为module1-dataSource和module2-dataSource。
以下是一个使用alias
元素定义别名的示例,其分别指定hello的别名为helloAlias1和helloAlias2。
<alias name="hello" alias="helloAlias1"/>
<alias name="hello" alias="helloAlias2"/>
<bean name="hello" class="java.lang.String">
<constructor-arg value="hello"/>
</bean>
1.2 class属性指定类型
在定义bean时可以通过class属性来指定当前bean对应的类型。class属性要求是对应Class类的全限定名,即需要包含包名的。如果我们需要定义的bean类型属于某个类的静态内部类,那么对应的class值应该是该内部类的二进制名称,即中间以$
符号连接。下面来看一个示例,假设我们有如下这样一个类,先需要分别定义Hello对应的bean和World对应的bean,其中Hello所在的包名为com.app
。
public class Hello {
public static class World {
}
}
那么,对应bean定义应该是这样子的:
<bean id="hello" class="com.app.Hello"/>
<bean id="world" class="com.app.Hello$World"/>
1.3 depends-on
depends-on
是定义在bean元素上的一个属性,用于指定其所依赖的bean,这样Spring将在初始化当前bean前先初始化其depends-on属性所指定的bean。所以depends-on的功能就是指定一个bean所依赖的bean,通过它来告诉Spring将优先初始化depends-on
属性指定的bean。注意,该属性只有告诉Spring该优先初始化哪个bean的功能,Spring不会因为这个属性的定义而注入对应的bean。在不使用depends-on
属性的情况下,Spring初始化bean的顺序是固定的,通常是根据bean定义的先后顺序来进行初始化。在下面的示例中,Spring将先初始化world,再初始化hello,但是其不会将world注入给hello。
<bean name="world" class="com.app.World"/>
<!-- 通过depends-on属性告诉Spring先初始化depends-on属性指定的bean,即这里的world -->
<bean id="hello" class="com.app.Hello" depends-on="world"/>
如果我们需要指定多个bean先于某个bean被初始化,我们也可以通过depends-on属性来指定,只是此时多个bean之间需要以逗号、分号或空格进行分隔。如下示例中就表示bean1依赖于bean2、bean3和bean4,即bean2、bean3和bean4需先于bean1被初始化。
<!-- 当依赖于多个bean时,多个bean之间以逗号、分号或空格进行分隔 -->
<bean id="bean1" class="com.app.Bean1" depends-on="bean2,bean3,bean4"/>
使用depends-on
属性后,depends-on属性指定的bean将先于该bean被初始化,但对于销毁而言,其是一个逆过程,即将先销毁该bean,再销毁depends-on
属性指定的bean。
1.4 lazy-init
默认情况下,Spring将在初始化bean容器的时候初始化所有的单例bean。如果我们有一个bean是单例的,但是又不想其在bean容器初始化的时候被初始化,那么我们可以在该bean上定义lazy-init
属性为true,这样Spring将不会在初始化bean容器的时候将其初始化。相对应的,其会在第一次被需要的时候进行初始化。所以如果我们有一个叫beanA的单例bean定义了lazy-init
为true,这就表示其不会在Spring初始化bean容器的时候进行初始化,但是如果其被另一个名叫beanB的单例bean所依赖,而beanB没有指定lazy-init
为true,这就意味着beanB将在Spring初始化bean容器时进行初始化,这个时候由于Spring需要给beanB注入一个beanA,也就是说beanA在这个时候被需要了,所以此时Spring也将会初始化beanA。
<!-- 通过lazy-init="true"指定其将不在初始化bean容器时初始化 -->
<bean id="beanA" class="com.app.BeanA" lazy-init="true"/>
<!-- 由于beanB对beanA有依赖,所以在初始化BeanB后,如果容器中不存在beanA,Spring将初始化备案A -->
<bean id="beanB" class="com.app.BeanB">
<property name="beanA" ref="beanA"/>
</bean>
lazy-init
的值默认是false,也就是说对于单例bean而言,如果没有指定lazy-init=”true”
时其默认会在bean容器初始化时被初始化,如果用户希望这种全局的初始化策略为不在bean容器初始化时进行初始化,则可以在beans元素上定义default-lazy-init=”true”
。
1.5 继承bean定义(parent)
试想一下,假设我们有一个类ParentA,其需要引用BeanA、BeanB和BeanC这三种类型的对象。然后针对于ParentA而言,我们又拥有三个子类ChildA、ChildB和ChildC。如果我们现在要定义ChildA、ChildB和ChildC三种类型的bean,依据传统的思想是不是就需要定义这三个bean,然后分别给这三个bean注入类型为BeanA、BeanB和BeanC的bean呢?Spring为我们提供了一种继承机制,它允许我们在定义一个bean时指定其对应的父bean,然后子bean将继承父bean的属性等,当然通过子bean注入的内容将覆盖父bean的内容,这里所谓的继承是对应bean定义的继承,不是真正意义上对象的继承。Spring允许我们在定义一个bean时通过parent属性来指定对应的父bean定义,其属性值对应父bean的id或name。所以针对于该应用场景,我们可以使用Spring的继承机制进行如下定义。
<?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.xsd">
<bean id="beanA" class="com.app.BeanA"/>
<bean id="beanB" class="com.app.BeanB"/>
<bean id="beanC" class="com.app.BeanC"/>
<bean id="parentA" class="com.app.ParentA">
<property name="beanA" ref="beanA"/>
<property name="beanB" ref="beanB"/>
<property name="beanC" ref="beanC"/>
</bean>
<bean id="childA" class="com.app.ChildA" parent="parentA"/>
<bean id="childB" class="com.app.ChildB" parent="parentA"/>
<bean id="childC" class="com.app.ChildC" parent="parentA"/>
</beans>
这时子bean也可以注入自己额外的内容,比如对于childA而言,它可以给自己注入一个beanD,这是没有问题的。当然,它也可以选择给自己注入一个特定的BeanA,此时childA自己注入的BeanA将覆盖其父bean持有的BeanA,即childA所拥有的BeanA将是其自身注入的那一个。
对于上述配置而言,将默认初始化所有的单例bean,所以上述配置中的parentA也将被初始化,如果我们不希望其被初始化,或者parentA是一个抽象类,根本就不能被初始化,我们可以在该bean上通过abstract=”true”指定该bean是抽象的,这样Spring将不会对其进行初始化,而仅仅把它当做其它bean定义的父bean定义而已。
<bean id="parentA" class="com.app.ParentA" abstract="true">
<property name="beanA" ref="beanA"/>
<property name="beanB" ref="beanB"/>
<property name="beanC" ref="beanC"/>
</bean>
如果我们的父bean不需要真正被初始化,只是用来作为一个父bean
定义供子bean
继承时,我们也可以不指定其对应的class
,但需要指定abstract=”true”
。这对实际应用是非常有用的,打个比方,如果我们的应用是通过XML
配置来管理对应的依赖关系的,同时我们的Dao都需要注入一个JdbcTemplate
,我们就无需在定义Dao对应bean
时给每个bean都定义注入一个JdbcTemplate
,而可以让它们都继承一个父级的bean
定义,然后在父级的bean
定义上去注入对应的JdbcTemplate
。如:
<bean id="parent" abstract="true">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="xxxDao" class="xxx.xxx.xxxDao" parent="parent"/>
1.6 description
通过description
元素指定当前bean
的描述信息,方便用户阅读。
<bean id="hello" class="com.app.Hello">
<description>当前bean的描述信息,便于阅读</description>
</bean>
(注:本文是基于Spring4.1.0所写)