I. 使用外部属性文件
从一般的开发可维护性角度来说,一些类似于数据库信息的配置文件,不应该被直接写进 java 类中,而是应该使用配置文件的方式,一方面,在配置文件需要改动的时候,我们并不需要去修改代码,直接修改配置文件即可,非常灵活;另外一方面,这也大大降低了出错的概率。
同理,在 Spring bean 的 xml 配置中, 这些信息也不应该被写进 xml 中,也应该放在配置文件里,Spring 提供了外部属性文件的方式,去加载配置的属性
- 在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如:
文件路径, 数据源 DataSource配置信息
等). 而这些部署细节实际上需要和 Bean 配置相分离
- Spring 提供了一个
PropertyPlaceholderConfigurer
的BeanFactory
后置处理器, 这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中. 可以在 Bean 配置文件里使用形式为${var}
的变量,PropertyPlaceholderConfigurer
从属性文件里加载属性, 并使用这些属性来替换变量. - Spring 还允许在属性文件中使用
${propName}
,以实现属性之间的相互引用。
举个例子,如果我们要配置一个数据库的 DataSource, 用 bean 的写法应该是类似于下面这种:
<bean id="dbDataSource" class="org.lovian.spring.db.DataSource">
<property name="user" value="root"/>
<property name="password" value="1234"/>
<property name="driver" value="com.mysql.jdbc.driver"/>
<property name="url" value="jdbc:mysql://test">
</bean>
这是一个普通的 Spring 单例 bean,value都是直接被写死的。能够从 ApplicationContext 中得到这个 dataSource 的实例。使用配置文件的方式,我们在 classpath 中,加入一个配置文件 resources/config/host.properties
user=root
password=1234
driver=com.mysql.jdbc.driver
url=jdbc:mysql://test
这个时候我们就可以用 Spring 提供的方式去加载这个配置:
<!-- import property file -->
<context:property-placeholder location="classpath:host.properties">
<bean id="dbDataSource" class="org.lovian.spring.db.DataSource">
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<property name="driver" value="${driver}"/>
<property name="url" value="${url}">
</bean>
这样 bean 生成的时候, value 值就根据 properties 文件中定义的来取。如果配置文件发生变化,我们也不需要去修改 xml 文件了
II. SPEL
SPEL, Spring 表达式语言(Spring Expression Language
), 是一个支持运行时查询和操作对象图的强大的表达式语言。
- 语法类似于
EL
, 使用#{...}
作为界定符,所有在花括号中的字符都被解析成 SPEL - SPEL 为 bean 的属性进行动态赋值提供了便利
通过 SPEL 可以实现:
- 通过 bean 的 id 对 bean 对象进行引用
- 调用方法以及引用对象的属性
- 计算表达式的值
- 正则表达式的匹配
1. SPEL 字面量
字面量的表示:
- 整数:
<property name="count" value="#{5}"/>
- 小数:
<property name="frequency" value="#{89.7}"/>
- 科学计数法:
<property name="capacity" value="#{1e4}"/>
- String可以使用单引号或者双引号作为字符串的定界符号:
<property name=“name” value="#{'Chuck'}"/>
或<property name='name' value='#{"Chuck"}'/>
- Boolean:
<property name="enabled" value="#{false}"/>
2. SPEL 引用 Bean、 属性和方法
- 引用其他对象
<!--通过 value 属性和 SPEL 配置 Bean 之间的应用关系-->
<property name="perfix" value="#{prefixGenerator}"/>
- 引用其他对象的属性
<!--通过 value 属性和 SPEL 配置 suffix 值为另一个 Bean 的suffix 属性值-->
<property name="suffix" value="#{sequenceGenerator2.suffix}"/>
- 调用其他方法,还可以链式操作
<!--通过 value 属性和 SPEL 配置 suffix 值为另一个 Bean 的suffix 返回值-->
<property name="suffix" value="#{sequenceGenerator2.toString()}"/>
<!-- 方法的连缀 -->
<property name="suffix" value="#{sequenceGenerator2.toString().toUpperCase()}"/>
- 调用静态方法或者静态属性: 通过
T()
调用一个类的静态方法
,它将返回一个Class Object
,然后再调用相应的方法和属性
<propery name="piValue" value="#{T(java.lang.Math).PI}"/>
3. SPEL 支持的运算符
- 算数运算符:
+, -, *, /, %, ^:
- 加号还可以用作字符串连接
- 比较运算符:
<, >, ==, <=, >=, lt, gt, eq, le, ge
- 逻辑运算符号:
and, or, not, |
- if-else 运算符:
?: (ternary), ?: (Elvis)
- 正则表达式:
matches
Share this on