第3章—高级装配—运行时注入
运行时注入
当我们经常用如下的硬解码方式来配置文件:
<bean id="SgtPeppers" class="com.CDDemo.SgtPeppers" p:title="sgt" p:song="Twinkle, twinkle, little start">
<property name="title" value="sgt"/>
<property name="song" value="Twinkle, twinkle, little start"/>
</bean>
但有时我们需要避免硬解码,需要想要这些值在运行时确定,Spring提供了两种在运行时求值的方式:
- 属性占位符
- Spring表达式语言(SpEL)
1.注入外部的值
在Spring中,处理外部值得最简单方式就是申明属性源并通过Spring的Enviroment来检索属性.例如:
@Configuration
@PropertySource("classpath:app.properties")
public class ExpressionTest {
@Autowired
Environment environment;
@Test
public BlankDisc disc(){
return new BlankDisc(
environment.getProperty("disc.title"),
environment.getProperty("disc.artist")
);
}
}
app.properties
disc.title="titeTest"
disc.artist="Twinkle, twinkle, little start"
2.深入学习Spring的Environment
Environment的getProperty()方法有四个重载的变种形式:
- String getProperty(String key)
- String getProperty(String key,String defaultValue)
- T getProperty(String key, Class<T> type)
- T getProperty(String key, Class<T> type,T defaultValue)
前两种形式的getProperty()方法都是返回String类型的值。后两种重载方法不是直接返回字符串,而是将获取到的值转化为指定类型的值,比如获取连接池中维持连接的总数量:
String disc = env.getProperty("disc.title","dukh");
除了属性相关的功能外,Environment还提供了一些方法来检查哪些profile处于激活状态:
- String [] getActiveProfiles():返回激活profile名称的数组;
- String [] getDefaultProfile():返回默认profile名称的数组;
- boolean acceptsPrifiles(String ... profiles):如果environment支持给定的profile返回true。
3.解析属性占位符
Spring一直支持将属性定义到外部的属性文件中,并使用占位符值将其插入到Spring bean中.在Spring装配中,占位符的形式为使用"${...}"包装的属性名称.
比如我们常见的使用数据库连接池的方式:
<!-- 读取db.properties文件. 读取到数据库信息 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
这里需要注意的是使用Spring context命名空间的<context:property-placeholder location="classpath:db.properties"/>元素将为你生成ProoertySourcesPlacehodlerConfigurer bean.
4.SpEL样例
SpEL的表达式是"#{...}"之中放入相应的计算或者方法调用等,如下所示:
@Value("#{T(System).currentTimeMillis()}") Long time
{T(System).currentTimeMillis()}最终计算的是当前时间的毫秒值.T()表达式会将java.lang.System视为java中对应的类型,因此可以调用其Static修饰的currentTimeMillis()方法.
表示字面值
浮点:
{3.14159}
科学计数法:98700
{9.87E4}
String:
{"Heloo"}
Boolean:
{false}
引用bean,属性和方法
将bean的ID作为SpEL表达式:
{SgtPeppers}
{SgtPeppers.title}
{SgtPeppers.play()}
还可以防止是null的情况 要先进行判断:
{SgtPeppers.play()?.toUpperCase()}
T()运算符的结果是一Class对象,它的真正价值在于它能够访问目标类型的静态方法和常量:
T(java.lang.Math).random()
5.SpEL运算符
SpEL提供了几种运算符,这些运算符可以用在SpEL表达式中的值上。
运算符类型 |
运算符 |
---|---|
算术运算 |
+、-、*、/、%、^ |
关系运算 |
<、>、==、<=、>=、lt、gt、eq、le、ge |
逻辑运算 |
and、or、not、| |
条件运算 |
?:(ternary)、?:(Elvis) |
正则表达式 |
matches |
数值运算
<!-- +运算符:两个数字相加 -->
<property name="adjustedAmount" value="#{counter.total + 42}"/>
<!-- +运算符:用于连接字符串 -->
<property name="fullName" value="#{performer.firstName + ' ' + performer.lastName}"/>
<!-- -运算符:两个数字相减 -->
<property name="adjustedAmount" value="#{counter.total - 20}"/>
<!-- *运算符:乘法运算 -->
<property name="circumference" value="#{2 * T(java.lang.Math).PI * circle.radius}"/>
<!-- /运算符:除法运算 -->
<property name="average" value="#{counter.total / counter.count}"/>
<!-- %运算符:求余运算 -->
<property name="remainder" value="#{counter.total % counter.count}"/>
<!-- ^运算符:乘方运算 -->
<property name="area" value="#{T(java.lang.Math).PI * circle.radius ^ 2}"/>
比较值
比较两个值是否相等,可以使用”==”运算符:
<!-- 假设equal属性为布尔属性 -->
<property name="equal" value="#{counter.total == 100}"/>
逻辑表达式
运算符 |
操作 |
---|---|
and |
逻辑AND运算操作,只有运算符两边都是true,表达式才能是true |
or |
逻辑OR运算操作,只要运算符的任意一边是true,表达式就会是true |
not或! |
逻辑NOT运算操作,对运算结果求反 |
<!-- and 运算符 -->
<property name="largeCircle" value="#{shape.kind == 'circle' and shape.perimeter gt 10000}"/>
<!-- ! 运算符 -->
<property name="outOfStock" value="#{!product.availiable}"/>
<!-- not 运算符 -->
<property name="outOfStock" value="#{not product.availiable}"/>
条件表达式
<!-- ?:三元运算符 -->
<property name="song" value="#{kenny.song != null ? kenny.song : 'Greensleeves'}"/>
正则表达式
<!-- 判断一个字符串是否是有效的邮件地址 -->
<property name="validEmail" value="#{admin.email matches '[a-zA-Z0-9.-%+-]+@[a-zA-Z0-9.-]+\.com'}"/>
- "开门待客"还是“送货上门”?
- 同步一个数据库要发多少个数据包?
- BP神经网络识别性别
- 为or、in平反——or、in到底能不能利用索引?
- BP神经网络续1
- 隐藏在程序旮旯中的“安全问题”
- SQLSERVER 占了500多M内存,原来的程序无法一次查询出50多W数据了,记录下这个问题的解决过程。
- 能自己“跑”的表单控件,思路,雏形,源码。vs2005版本
- 在SQLMAP中使用动态SQL
- 使用OQL“语言”构造ORM实体类的复杂查询条件
- AdoHelper使用MySQL存储过程示例
- 使用8位字节的编码格式将字节流安全的转换成String
- 同样的SQL语句在查询分析器执行很快,但是网站上执行超时的诡异问题
- PDF.NET数据开发框架操作MySQL实体类操作实例
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- C#将引用的dll嵌入到exe文件中
- C# 软件版本号
- C# 实现登录并跳转界面
- QT 常用控件操作实例集锦
- C# Socket TCP发送图片与接收图片
- ingress通过daemonSet,nodeSelector,hostNetwork方式部署
- Oracle参数解析(event)
- Qt读写文件(2种方式)实现详解
- 字符串匹配 - KMP算法
- c# 判断文件是否发生了变化
- C# 用IrisSkin4.dll美化你的WinForm
- Oracle参数解析(shared_pool_size)
- C# GTS四轴运动控制器实例(固高科技步进电机不带编码器)
- Oracle参数解析(pre_page_sga)
- C#简单爬取数据(.NET使用HTML解析器NSoup和正则两种方式匹配数据)