本文将会介绍Spring框架中wiring beans的相关内容,包括:bean的声明与创建、在xml文件中对bean基本使用方法的配置以及Spring 3中新特性Spring Expression Language(即SpEL)的初步介绍。
在引出bean之前,不得不提到container。Container用于描述包含并维护其他组件(component)的组件。在Spring框架中,提供了两种Container,即BeanFactory和ApplicationContext。其中,BeanFactory是最简单的一种Container,能够提供基本的依赖注入(DI)和wring bean的服务。而当需要使用到更加高级的Spring框架服务,例如Spring AOP、事件传递及各种不同应用层的context实现等时,则ApplicationContext能够显示出其优势。而提及bean,则可以简单地理解为是经过实例化,编译的对象。它是由container进行管理的。
下面开始详细介绍bean在Spring中的配置。
以下代码是一个典型的Spring中beans的xml配置。其中bean的声明处于
- package org.Spring.demo;
- public class Movie {
- private movieName;
- private introInfo;
- public Movie() {
- }
- public Movie(String movieName, String introInfo) {
- this.movieName = movieName;
- this.introInfo = introInfo;
- }
- public void display() {
- system.out.println(movieName + ":" + introInfo);
- }
- }
以下是电影TheStarWar作为Movie的一个实例而被定义为一个Spring bean:
- xml version="1.0" encoding="UTF-8" ?>
- <beans xmlns="http://springframework.org/schmema/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 id="StarWars" class="com.Spring.demo.Movie" >
- <constructor-arg value="Star Wars" />
- <constructor-arg value="bla bla bla bla" />
- bean>
- beans>
其中,class="com.Spring.demo.Movie"和Java代码进行关联,从而根据xml文件中的值进行Movie的实例化,最终结果得到名为Star Wars的实例StarWars。此时,我们便可以使用ApplicationContext对象来使用已经配置过的xml:
- ApplicationContext ctx = new ClassPathXmlApplicationContext(
- "com/Spring/demo/spring-demo.xml");
- Movie starWars = ctx.getBean("StarWars");
- starWars.display();
另外情况是,Movie的构造函数的一个参数另外一个对象,例如,Movie对象的构造函数多了一个Music类型的参数(背景音乐的需要),则需在xml配置中增加一个构造函数参数:
- <constructor-arg ref="ANewHopeandEndCredits">
属性'ref'代表了一种引用关系。它是另外一个类型为Music,并已于beans内定义的实例。此处,Music类的详细定义暂且略去。
除此之外,我们知道bean是有一个生命周期的。Spring为其提供了两个beans的属性:default-init-method, default-destory-method。它们分别对应类的某个特定方法。
我们知道,在很多时候一个类里面存在setters和getters方法。例如,上述例子中,引入了Music类型的字段之后,可能出现情形:
- private Music music ;
- public void setMusic(Music music) {
- this.music = music;
- }
- public Music getMusic() {
- return music;
- }
针对这种情况,Spring提供了与construct-arg平行的标签:
- <property name="music" ref="ANewHopeandEndCredits" />
当然,此处的ref表示的是引用类型,该类型一再beans中定义。如果是值类型,则可以直接使用value属性。
Spring还提供了一种内部bean的形式,即在bean的内部定义另外一个bean,以达到使用目的。这种方式和引用方式的区别在于,引用方式所引用的bean被定义在
接下来所说的是Spring对集合类型的装载。体现在四个集合类型中:、
- <property name="music">
- <list>
- <ref bean="EnterLordVader" />
- <ref bean="ANewHopeandEndCredits" />
- list>
- property>
类似的,
- <property name="music">
- <map>
- <entry key="Enter Lord Vader" value="EnterLordVader" />
- <entry key="A New Hope and End Credits" value="ANewHopeandEndCredits" />
- map>
- property>
为了方便起见,现将music设想为Properties类型的。于是
- <property name="music">
- <props>
- <prop key="EnterLordVade">Enter Lord Vadeprop>
- <prop key="ANewHopeandEndCredits">A New Hope and End Creditsprop>
- props>
- property>
需要注意的是,Spring同时也提供了null的装载。这是由于有些属性在未被赋值之前,需要保持为空。举例如下:
- <property name="someNonNullProperty"><null/>property>
最后要说的当然是SpEL。这一特性在Spring 3中得以引进。它的一般使用方式是:
- <property name="count" value="#{5}"/>
SpEL在以下的点上提供了便捷方式:通过对bean的ID来引用bean;对对象方法的调用和属性访问;提供算术,关系以及逻辑的运算;正则表达式的匹配;对集合的操作。首先,第一点,引用bean:
- <property name="ANewHopeandEndCredits" value="#{ANewHopeandEndCredits}"/>
和
- <property name="ANewHopeandEndCredits" ref="ANewHopeandEndCredits">
是等价的。但不同的是,我们可以使用如下方式:
- <property name="ANewHopeandEndCredits" value="#{ANewHopeandEndCredits.getName()}"/>
即调用对象的方法(或可以访问对象的属性值)。这就是上述所说的SpEL的优势之二。在算术、关系和逻辑运算中,类似于在“#{}”中的括号里编写Java代码。拿下例来说:
- <property name="average" value="#{counter.total / counter.count}"/>
这是一个简单的除运算。(有趣的是,SpEL提供了^操作,而Java没有。)关系运算需要注意的地方是,大于或者小于号和xml的书写规则会冲突,于是S平EL提供了eq,lt,le,gt,ge分别表示==,<,<=,>,>=。逻辑运算关键词分别有:and,or,not以及!。注意,S平EL并没有提供“&&”或者“||”符号代表and和or。另外,三木运算方式和Java的书写方式也是类似的。而对于正则表达式匹配,SpEL提供了matches关键字,这里不再过多阐述。
对集合的操作,SpEL提供了类似Java操作集合的机制。下面以一个例子为例:
- package com.Spring.cities;
- public class City {
- private String name;
- private String province;
- public String getName() {
- return this.name;
- }
- public String getProvince() {
- return this.province;
- }
- public void setName(String name) {
- this.name = name;
- }
- public void setProvince(String province) {
- this.province = province;
- }
- }
以下代码使用Spring的
- <util:list id="cities">
- <bean class="com.Spring.cities.City"
- p:name="Chengdu" p:province="Sichuan" />
- <bean class="com.Spring.cities.City"
- p:name="Guangzhou" p:province="Guangdong" />
- <bean class="com.Spring.cities.City"
- p:name="Xian" p:province="Shanxi" />
- <bean class="com.Spring.cities.City"
- p:name="Yinchuan" p:province="Ningxia" />
- util:list>
此时,我们就可以使用SpEL筛选具体的城市:
- <property name="chosenCity" value="#{cities[2]}"/>
与使用
- <property name="cityNames" value="#{cities.![name]}"/>
当只是需要得到城市名,而不需要得到全部的城市信息时,使用以上代码,可以直接映射之前所定义的城市集合中,各城市的名称部分信息集合。
需要注意的是,虽然使用SpEL可以减少Java代码的编写工作,但是过多的使用会带来一些负面的影响。这种方式不好编写测试代码,同时也没有IDE的支持,以检查语法问题。
至此,对bean的基本使用方式已经介绍得差不多了。