本章主要继续介绍spring基于XML装配bean的知识,主要介绍spring对属性的注入。
设值注入简单值和引用其他bean:
package org.robbie.test.spring.beans; public interface Instrument { void play(); }
package org.robbie.test.spring.beans; public class Flute implements Instrument { @Override public void play() { System.out.println("play flute"); } }
package org.robbie.test.spring.beans; import org.robbie.test.spring.exception.PerformerException; import org.robbie.test.spring.inf.Performer; public class Instrumentalist implements Performer { private String song; private Instrument instrument; public Instrumentalist() { } @Override public void perform() throws PerformerException { } public String getSong() { return song; } public void setSong(String song) { this.song = song; } public Instrument getInstrument() { return instrument; } public void setInstrument(Instrument instrument) { this.instrument = instrument; } }
<?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 id="instrumentalist" class="org.robbie.test.spring.beans.Instrumentalist"> <property name="instrument" ref="flute"></property> <property name="song" value="god is a girl"></property> </bean> <bean id="flute" class="org.robbie.test.spring.beans.Flute"></bean> </beans>
注入内部bean:
上面的例子也可以写成:
<?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 id="instrumentalist" class="org.robbie.test.spring.beans.Instrumentalist"> <property name="instrument"> <bean class="org.robbie.test.spring.beans.Flute"></bean> </property> <property name="song" value="god is a girl"></property> </bean> </beans>
内部bean的注入也可以用于构造器注入:例如
<?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 id="instrumentalist" class="org.robbie.test.spring.beans.Instrumentalist"> <constructor-arg> <bean class="org.robbie.test.spring.beans.Flute"></bean> </constructor-arg> <property name="song" value="god is a girl"></property> </bean> </beans>
从上面的例子可以看出, 内部bean适用于一次性注入,不能被复用,也没有ID(可以给ID,但是没有用处),并且影响XML的可读性,这样的配置方式比较少见,在项目中谨慎适用。
适用命名空间装配属性
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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="instrumentalist" class="org.robbie.test.spring.beans.Instrumentalist" p:song="god is a girl" p:instrument-ref="flute"> </bean> <bean id="flute" class="org.robbie.test.spring.beans.Flute"></bean> </beans>
上面的例子增加了一段命名空间配置:
xmlns:p="http://www.springframework.org/schema/p"
装配集合属性
集合元素 | 用途 |
<list> | 装配list类型的值,允许重复 |
<set> | 装配set类型的值,不允许重复 |
<map> | 装配map类型的值,名称和值可以为任意类型 |
<props> | 装配properties类型的值,名称和值必须为string类型 |
装配List,Set和Array
package org.robbie.test.spring.beans; import java.util.Collection; public class Band { private Collection<Instrument> instruments; public Collection<Instrument> getInstruments() { return instruments; } public void setInstruments(Collection<Instrument> instruments) { this.instruments = instruments; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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="flute" class="org.robbie.test.spring.beans.Flute"></bean> <bean id="guita" class="org.robbie.test.spring.beans.Guita"></bean> <bean id="piano" class="org.robbie.test.spring.beans.Piano"></bean> <bean id="band" class="org.robbie.test.spring.beans.Band"> <property name="instruments"> <list> <ref bean="flute" /> <ref bean="guita" /> <ref bean="piano" /> </list> </property> </bean> </beans>
如果属性不为集合,而是数组,例如Instrument[] instruments也同样适用以上配置。
以下为Set集合装配
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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="flute" class="org.robbie.test.spring.beans.Flute"></bean> <bean id="guita" class="org.robbie.test.spring.beans.Guita"></bean> <bean id="piano" class="org.robbie.test.spring.beans.Piano"></bean> <bean id="band" class="org.robbie.test.spring.beans.Band"> <property name="instruments"> <set> <ref bean="flute" /> <ref bean="guita" /> <ref bean="piano" /> </set> </property> </bean> </beans>
Map集合装配
package org.robbie.test.spring.beans; import java.util.Map; public class Band { private Map<String, Instrument> instruments; public Map<String, Instrument> getInstruments() { return instruments; } public void setInstruments(Map<String, Instrument> instruments) { this.instruments = instruments; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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="flute" class="org.robbie.test.spring.beans.Flute"></bean> <bean id="guita" class="org.robbie.test.spring.beans.Guita"></bean> <bean id="piano" class="org.robbie.test.spring.beans.Piano"></bean> <bean id="band" class="org.robbie.test.spring.beans.Band"> <property name="instruments"> <map> <entry key="flute" value-ref="flute"></entry> <entry key="guita" value-ref="guita"></entry> <entry key="piano" value-ref="piano"></entry> </map> </property> </bean> </beans>
属性 | 用途 |
key | 指定map中entry的键为String |
key-ref | 指定map中entry的键为spring上下文中其他bean的引用 |
value | 指定map中entry的值为String |
value-ref | 指定map中entry的值为spring上下文中其他bean的引用 |
装配properties集合
package org.robbie.test.spring.beans; import java.util.Properties; public class Band { private Properties instruments; public Properties getInstruments() { return instruments; } public void setInstruments(Properties instruments) { this.instruments = instruments; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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="band" class="org.robbie.test.spring.beans.Band"> <property name="instruments"> <props> <prop key="guita" >guita</prop> <prop key="piano" >piano</prop> <prop key="flute" >flute</prop> </props> </property> </bean> </beans>
装配空值:
在某些特定情况下,如果全局变量给定了一个默认的值,但是在创建对象的时候,又想为整个变量设置为空时,可以采用spring的空值注入。
<property name="instruments"><null /></property>
使用表达式装配:
之前所有的基于XML的装配都成为静态装配,如果在某些时候需要在运行期动态的对spring bean进行装配的话需要用到springEL(Spring Expression Language),springEL是用一种表达式,通过计算在运行期进行bean的装配,包括对属性和构造参数的装配等,通过使用springEL可以达到难以想象的动态装配效果。
SpringEL拥有很多特性,包括:
使用bean的ID来引用bean |
调用方法和访问对象的属性 |
对值进行算术、关系、逻辑运算 |
正则表达式匹配 |
集合操作 |
SpringEL中的字面值:
整形:
<property name="property" value="#{5}"></property>
浮点型:
<property name="property" value="#{89.3}"></property>
科学计数:
<property name="property" value="#{1e4}"></property>
字符串型:
<property name="name" value="#{'name'}"></property>
<property name="name" value='#{"name"}'></property>
单引号和双引号都支持
布尔型:
<property name="name" value="#{false}"></property>
引用bean、properties和方法
通过bean的id引用bean:
<property name="property" value="#{otherBean}"></property>
引用其他bean的属性:
<property name="property" value="#{otherBean.property}"></property>
引用其他bean的调用方法:
<property name="name" value="#{otherBean.method()}"></property>
可以调用工具方法进行结果处理:
<property name="name" value="#{otherBean.method().toUpperCase()}"></property>
如果方法返回空值,则会抛出异常,如果要避免异常出现可以使用如下写法:
<property name="name" value="#{otherBean.method()?.toUpperCase()}"></property>
操作类
调用静态方法和属性以及常量可以使用:
<property name="name" value="#{T(java.lang.Math).PI}"></property>
在SpEL上执行的操作:
运算符类型 | 运算符 |
算数运算 | +,-,*,/,%,^ |
关系运算 | <,>,==,>=,<=,It,gt,,le,ge,eq |
逻辑运算 | and, or , not, | |
条件运算 | ?: |
正则表达式 | matchs |
数值运算:
<property name="name" value="#{juggler.total + 40}"></property> <property name="name" value="#{juggler.total / 40}"></property> <property name="name" value="#{juggler.total * 40}"></property> <property name="name" value="#{juggler.total % 40}"></property>
比较运算:
<property name="name" value="#{juggler.total == 40}"></property> <property name="name" value="#{juggler.total > 40}"></property> <property name="name" value="#{juggler.total lt 40}"></property>
逻辑运算:
<property name="name" value="#{juggler.total > 40 and juggler.total < 80}"></property> <property name="name" value="#{juggler.total > 40 or juggler.total < 80}"></property> <property name="name" value="#{not juggler.total > 40}"></property>
三元运算:
<property name="name" value="#{juggler.total == 40 ? '1' : '2'}"></property>
三元运算变体:
<property name="name" value="#{juggler.total ?: '2'}"></property>
以上表达为如果juggler.total不为空则为本身的值,如果为空就为2
正则表达式:
<property name="name" value="#{juggler.name matchs '[a-zA-z0-9._%+-]+'}"></property>
在SpEL中筛选集合:
<property name="name" value="#{cities[2]}"></property>
cities为在spring中定义的集合,该例为方位该集合中的第三个元素
调用集合中的方法:
<property name="name" value="#{cities[2].size()}"></property>
访问map集合:
<property name="name" value="#{cities['key']}"></property>
读取properties文件中的值:
<util:properties id="settings" location="classpath:settings.properties"></util:properties> <bean id="flute" class="org.robbie.test.spring.beans.Flute"> <property name="name" value="#{settins['name']}"></property> </bean>
访问spring内置特殊属性的值:
访问环境变量:
<property name="name" value="#{systemEnvironment['JAVA_HOME']}"></property>
访问启动参数:
<property name="name" value="#{systemProperties['application.home']}"></property>
查询集合成员:
使用.?[]
<property name="bigCities" value="#{cities.?[population gt 10000]}"></property>
查询集合cities中人口数大于10000的城市元素,并将这些元素注入进属性当中
查询第一个匹配项:
<property name="bigCities" value="#{cities.^[population gt 10000]}"></property>
查询集合cities中第一个匹配人口大于10000的元素,并进行属性注入
查询最后一个匹配项:
<property name="bigCities" value="#{cities.$[population gt 10000]}"></property>
查询集合cities中最后一个匹配人口大于10000的元素,并进行属性注入
投影集合(根据某种条件筛选出一个新的集合)
<property name="bigCities" value="#{cities.![name]}"></property>
把集合cities中每个元素的name属性进行重新组织,形成一个新的集合,然后将这个新的集合注入进属性当中
先查询集合再投影集合:
<property name="bigCities" value="#{cities.?[population gt 10000].![name]}"></property>
在cities中查询人口大于10000的元素,并把这个元素的name属性的值重新组织成一个新的集合,将这个新的集合注入进属性当中
SpEL非常的灵活,但是最终只是一组字符串的表达式,没有任何的校验,容易出现错误,按照书籍理解,如果传统的装配方式不能够满足时,再考虑SpEL方式进行装配。