Spring:传统的XML文件装配Bean

在Spring这个基于容器的框架中,一般很少采用new的方式来创建类的对象,一般是在XML文件中,对类进行实例化。

Spring3.0除了传统的XML文件中进行装配bean,还可以进行基于java注解的方式来配置。这里主要介绍下XML的形式。

a、简单装配

1、简单的bean声明

首先定义一个简单的学生类,只有一个构造函数

package com.springTest.school;

public class Student{
    public Student(){}
}
针对上面的学生类,在XML文件中进行bean的声明

	<bean id="xiaoming" class="com.springTest.school.Student"></bean>
可以看出,我们声明了一个小明的实例。


2、通过构造器注入

2.1、基本类型

上面的学生类型什么都没有,只有单一构造函数,学生应当具有姓名、年龄等属性。

<pre name="code" class="java">package com.springTest.school;

public class Student{
    private int age;
    private String name;
    public Student(){}
    public Student(String name,int age){
          this.name=name;
          this.age=age;
    }
}

 这时候,我们可以简单的声明bean,也可以让小明具有一个初始化的年龄和姓名。如下,xiaoming是一个名字为mingming的15岁骚年。 
	<bean id="xiaoming" class="com.springTest.school.Student">
	<constructor-arg value="mingming"/>
	<constructor-arg value="15"/>
	</bean>

2.2、对象引用

Student类中的学生,可以会跳舞,会游泳,会打篮球、会吟诗等各项特长(先假设每一个学生都只有一个特长,后面会让他们多学点)。这时候,学生类又要改变下。

package com.springTest.school;

public class Student{
    private int age;
    private String name;
    <span style="font-family: Arial, Helvetica, sans-serif;">private SpecialTalent specialTalent;//特长</span>
    public Student(){}
    public Student(String name,int age,SpecialTalent specialTalent){
          this.name=name;
          this.age=age;
          this.specialTalent=specialTalent;
    }
    public void play(){specialTalent.show();}//展示特长,为了区别好理解,用play来表示
}
其中特长是一个接口
package com.springTest.school;

public interface SpecialTalent{
    void show();
}
各种特长都实现该接口

package com.springTest.school;
//游泳
public class Swim{

    public void show(){
          System.out.println("I can swim");
    }
}
package com.springTest.school;
//跳舞
public class Dance{

    public void show(){
          System.out.println("I can dance");
    }
}
package com.springTest.school;
//打篮球
public class Basketball{

    public void show(){
          System.out.println("I can play basketball");
    }
}
OK,现在我们再也不能向之前一样,通过构造函数来初始化一个学生的属性,因为学生的属性中,不在是只有基本类型,而是添加了特长,这个时候初始化构造函数,还是有其他的方法可以做到的。

首先,我们把各种特长的bean声明出来。

<bean id="dance" class="com.springTest.school.Dance"></bean>
<bean id="swim" class="com.springTest.school.Swim"></bean>
<bean id="basketball" class="com.springTest.school.BasketBall"></bean>
然后,我们声明学生的bean的时候,通过构造函数来初始化属性。

<bean id="xiaoming" class="com.springTest.school.Student">
	<constructor-arg value="mingming"/>
	<constructor-arg value="15"/>
        <constructor-arg ref="swim">
	</bean>


<bean id="xiaokong" class="com.springTest.school.Student">
	<constructor-arg value="kongkong"/>
	<constructor-arg value="15"/>
        <constructor-arg ref="dance">
	</bean>
这个时候,两个学生,都有某些属性。


3、注入bean属性(通过property)

3.1、属性为单个值的注入

我们上面看到了通过构造函数注入,现在把构造函数干掉,这个时候,如何在XML文件中配置值呢?使用property来注入属性,这个时候也是两类,一类是基础类型的属性,一类是扩展类型的属性。

这时候,Student的类如下:

package com.springTest.school;

public class Student{
    private int age;
    private String name;
    private SpecialTalent specialTalent;//特长
    public Student(){}
    public void setName(String name){this.name=name;}
    public String getName(){return name;}
    public void setAge(int age){this.age=age;}
    public int getAge(){return age;}
    public void setSpecialTalent(SpecialTalent specialTalent){this.specialTalent=specialTalent;}
    public SpecialTalent getSpecialTalent(){return specialTalent;}
  
    public void play(){specialTalent.show();}
}
可以发现,我们不但干掉了带有参数的构造函数,还添加了每一个属性的set、get函数。

这个时候,在XML文件中注入,还是可以为类的属性赋值。Spring能够借助属性的set方法来配置属性的值,从而实现注入。

至于说上面的类属性中,除了基本类型外,还有引用类型,根据之前我们通过构造函数注入的方法,也可以类似的对引用类型进行XML的bean注入。

<bean id="xiaoma" class="com.springTest.school.Student">
<property name="name" value="xiaomage" />
<property name="age" value="17" />
<property name="specialTalent" ref="swim">
</bean>
通过上面的配置可以看出,小马哥是一个擅长游泳的17岁骚年。

这里的property是通过类属性的setXX()方法来进行注入的,如年龄age,property会调用setAge()方法将age的值设置为17。这里age是int类型,可以看出,spring在赋值时会自动转换的。

要注意的一点:<property>的作用不仅仅是依赖注入装配硬编码的值,而是将不同的对象组织在一起,如上面的xiaoma,swim。


3.2、属性为集合的注入

3.2.1、List、Set类型

我们的学生都是多才多艺的,不会只有一个特长,因此,特长这一属性,需要变成复数的。

private List<SpecialTalent>    specialTalents; 

public void setSpecialTalent(List<SpecialTalent>    specialTalents){this.specialTalents=specialTalents;}
这个时候如何装配呢?经过下面的装配,小马哥瞬间会游泳、跳舞、打篮球。
<bean id="xiaoma" class="com.springTest.school.Student">
<property name="name" value="xiaomage" />
<property name="age" value="17" />
<property name="specialTalents">
<list>
 <ref bean="swim"/>
 <ref bean="basketball"/>
 <ref bean="dance"/>
</list>
</property>
</bean>
我们这里用的是List,集合Set也是类似的。Map、Properties有些不同,下面简单介绍下。

3.2.2、Map类型

特长用Map定义

private Map<String,SpecialTalent>    specialTalents; 

public void setSpecialTalent(Map<String,SpecialTalent>    specialTalents){this.specialTalents=specialTalents;}

装配如下:

<bean id="xiaoma" class="com.springTest.school.Student">
<property name="name" value="xiaomage" />
<property name="age" value="17" />
<property name="specialTalents">
<map>
 <entry key="SWIM" value-ref="swim"/>
 <entry key="DANCE" value-ref="dance"/>
</map>
</property>
</bean>
这里提到几个,一般都是key-value的模式,如果是引用就加上-ref,所以,共有key、key-ref、value、value-ref四种。

3.2.3、Properties类型

特长用Properties定义

private Properties   specialTalents; 

public void setSpecialTalent(Properties   specialTalents){this.specialTalents=specialTalents;}
XML装配如下:

<bean id="xiaoma" class="com.springTest.school.Student">
<property name="name" value="xiaomage" />
<property name="age" value="17" />
<property name="specialTalents">
<props>
 <prop key="SWIM">ssss</prop>
 <prop key="DANCE">hhhhh</prop>
</props>
</property>
</bean>
这里需要注意的是,properties中,适用于key、value都是String类型的情况。

3.3、注入内部Bean

如果游泳、跳舞等都没有自己注入bean,或者我们想自己单独使用一个,这时候可以用到内部bean

<bean id="xiaoma" class="com.springTest.school.Student">
<property name="name" value="xiaomage" />
<property name="age" value="17" />
<property name="specialTalent">
<bean class="com.springTest.Swim"/>
</property>
</bean>
内部bean是很直接的将需要引用的类内部引用,所以没有ID属性。内部bean适用于一次注入,不能够被复用。

3.4、命名空间p装配属性

这是一种完全等价于property的方法,需要在XML的beans属性中加上:xmlns:p="http://www.springframework.org/schema/p"

然后写XML时候看起来会很简洁。

<bean id="xiaoma" class="com.springTest.school.Student"
p:name=xiaoming 
p:age="19"
p:specialTalent-ref="swim" />

3.5、装配空值

为属性设置空值,看起来很没用,但是实际我们的很多值,虽然初始状态是空,却在实际运行时,会赋予默认值,如果非要使用空值,就得在XML装配下了。
<property name="someNonNullProperty"><null/></property>

4、Bean的作用域

Spring Bean默认都是单例,容器分配一个Bean时,总会返回Bean的同一个实例。
但是,上面的学生,总不能每一个学生都是xiaoming啊,所以,可以通过作用域来控制,让Spring在每次请求时都为bean产生一个新的实例。
<bean id="xiaoming" class="com.springTest.school.Student" scope="prototype" />
这样每一次请求xiaoming这个bean,总会产生一个新的学生,注意了,并不是所有学生都叫xiaoming,这里的xiaoming只是一个ID。

Singleton:在每一个Spring容器中,一个bean定义只有一个对象实例(默认就是这样)。

prototype:允许bean的定义可以被实例化任意次(每次调用产生一个实例对象)。

request:在一次http请求中,每一个bean定义对应一个实例。该作用域仅在基于web的Spring上下文(例如springmvc)中才有效。

session:在一个httpsession中,每一个bean定义对应一个实例。该作用域仅在基于web的Spring上下文(例如springmvc)中才有效。

global-session:在一个全局httpsession中,每一个bean定义对应一个实例。该作用域仅在portlet上下文中才有效。


5、bean的初始化、销毁时的处理

这里简单介绍下,XML文件中,还可以让实例在创建、销毁时,执行特定的方法。多说无益,看码。

<bean id="xiaoming" class="com.springTest.school.Student" 
init-method="enterSchool"
destroy-method="leaveSchool" />
学生在实例化之前,需要进入学校,销毁学生身份之前,需要离开学校,这才是完整的周期啊。其中enterSchool、leaveSchool是两个方法。

接下来问题来了,一个人如果不到学校工作,那就不是老师,不离开学校,那就不能说他不是老师。所以,老师这个类实例化之前,也需要enterSchool,辞职前,也需要leaveSchool。好吧,那老师类实例化也需要加上两个必须执行的方法。那么,校长呢,教务主任呢,校工呢,都需要,总不能每一个都写一下吧,有办法解决的。

在XML文件的beans配置中,添加默认执行的属性:

default-init-method="enterSchool"
default-destroy-method="leaveSchool"

b、使用表达式装配


Spring3引入了Spring表达式语言(SpEL),SpEL是比较简洁的装配bean的方式,通过运行期执行的表达式将值装配到bean的属性或者构造器参数中。

SpEL的特性:

1、使用bean的ID来引用bean;

2、调用方法和访问对象的属性;

3、对值进行算术、关系、逻辑运算;

4、正则表达式匹配;

5、集合操作。

1、字面值表达式

这个其实使用的不多,也就是一个字面值,然后就获取到字面值。

憋说话,看码。

<pre name="code" class="html"><property name="name" value="#{'xiaoming'}" />
<property name="age" value="#{17}" />
<pre name="code" class="html"><property name="manOrNot" value="#{false}" />

 
<property name="name" value='#{"xiaoming"}' />
 第一个就是表达式里面的xiaoming,第二个17岁,第三个不是爷们,第四个是为了区分第一个,看单引号、双引号,这俩其实都一样。 

2、引用bean、properties和方法

上面我们说过一个学生要有特长,小明很牛,有小马的所有特长,这时候,可以用bean的表达式。

<bean id="xiaoming" class="com.springTest.school">
<property name="specialTalents" value="#{xiaoma.specialTalents}" />
</bean>
看吧,小明不需要列举自己会游泳、唱歌、跳舞,只需要说我跟小马的特长一样,cool。

上面其实等价于:

Student xiaoming=new Student();
xiaoming.setSpecialTalents(xiaoma.getSpecialTalents());
如果小明要表演一个特长,那么他可以表演人意一个,这时候,可以搞一个随机的函数,让他表演,这时候,给student类添加show属性。

<property name="show" value="#{RandomShow.selectShow()}" />
这时候,上面返回的如果是String,我们可以再来一个大小写的转变

<property name="show" value="#{RandomShow.selectShow()?.toUpperCase()}" />
上面为啥用了个问号?,这个是有原因的,因为可能selectshow返回null,这时候,如果不用问号,就会爆出空指针异常,加了就不会啦,这个不错。


3、操作类

主要就是使用类作用域的方法、常量等。举个例子,不举。
<property name="randomNumber" value="#{T(java.lang.Math).random()}" />
T()主要价值在于可以访问指定类的静态方法和常量。























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值