注入外部值
在spring中,处理外部值的最简单的办法就是声明属性源并通过Spring的Environment来检索属性。
@Configuration
@PropertySource("classpath:/com.soundsystem.app.properties")
public class Demo{
@Autowired
Environment env;
@Bean
public A method(){
return new B(
env.getProperty("dise.title"),
evn.getProperty("dise.artist")
);
}
}
在本例中,@PropertySource引用了类路径中一个名为app.properties的文件。他大概会是如下所示:
disc.title=XXXXXXX disc.artist=xxxxxxxxxx
这个属性文件会加载到spring的Environment中,稍后可以从这里检索属性。同时在method方法中会创建一个新的Demo,他的构造器参数是从属性文件中获取的,而这是通过getPeoperty()实现的。
深入学习Spring 的Environment
Environment类的getProperty()方法有四个重载的变种形式。
String getProperty(String key)
String getProperty(String key,String defaultValue)
T getProperty(String key,Class type)
T getProperty(String key,Class type,T defaultValue)
前两种的getProperty()方法都会返回String类型的值。
下面两种不会将所有的返回值都视为String类型。
defaultValue代表如果没有获取到值,则使用defaultValue所写的值。
如果想要检查某个属性是否存在的话,可以是调用Environment的containsProperty()方法,该方法返回布尔类型。
除了属性相关功能外,Environment还提供了一些方法来检查哪些profile处于激活状态。
String[] getActiveProfile():返回激活profile名称的数组
String[] getDefaultProfiles():返回默认的profile名称数组
boolean acceptsProfiles(String ...profile):environment支持给定profile的话,就返回true。
解析占位符
spring一直支持将属性定义到外部的属性文件中,并使用占位符将其插入到spring的bean中。在Spring 的装配中,占位符的形式为使用${...}包装的属性名称。
使用Spring表达式语言进行装配
Spring3引入了Spring表达式语言(Spring Expression Language,SpEL),他能够以一种强大和简洁的方式将值装配到bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时进行计算,得到值。使用SqEl,你可以实现超乎想象的装配效果,这是使用其他的装配技术难以做到的。
SqEl拥有很多特性,包括:
使用Bean的id来引用bean
调用方法和访问对象的属性
对值进行算术,关系和逻辑运算
正则表达式匹配
集合操作
SpEL样例
SpEL表达式要放到"#{...}"之中,这与属性占位符有些类似,属性占位符要放到"${...}"之中。
#{1} 除去"#{}"标记之后,剩下的就是SpEL表达式了,也就是一个数字常量。这个表达式的计算机结果就是数字1。
#{T(System).currentTimeMillis()}
他的最终结果是计算表达式的那一刻的当前时间的毫秒值。T()表达式会将java.lang.System视为java中对应的类型,由此可以调用其static修饰的currentTimeMillis()方法。
SpEL表达式也可以引用其他的bean或其他bean的属性。例如,下面的这个表达式会得到ID为sgtPeppers的bean的artist属性。
#{sgtPeppers.artise}
我们还可以通过systemProperties对象引用系统属性。
#{systemProperties['disc.title']}
表示字面值
SpEL可以表示整数,浮点数,String和Boolean。
在SpEL中使用字面值其实没有太大的意义。
引用bean,属性和方法
SpEL表达式所能做的另外一件事就是 通过ID引用其他的bean。还可以动过.来引用bean中的属性。
#{sgtPeppers.artist}
除了引用bean的属性,我们还可以调用bean上的方法。例如,假设有另外一个bean,他的ID为artistSelector,我们可以在SpEL表达式中按照如下的方式来调用bean的selectArtist()方法:
#{artistSelector,selectArtist()}
对于被调用方法的返回值来说,我们同样可以调用返回值的方法,例如,如果selectArist返回的值是String类型,那么我们可以调用toUpperCase()将整个结果改为大写字母形式。
如果selectArtist()的返回值不是null,那没什么问题。但是为了避免出错,我们可以使用类型安全的运算符:
#{artistSelector.selectArtist()?.toUpperCase()}
使用“?.”运算符能够在访问它右边的内容之前,确保他所对应的元素不是null。
在表达式中使用类型
如果要在SpEL中访问类作用域的方法和常量的话,要依赖T()这个关键的云算符。例如,要在SpEL中表达java的Math类,需要按照如下方式使用T()云算符:
T(java.lang.Math)
这里的T()云算符结果会是一个Class对象,也就是类的实例,代表了java.lang.Meth。如果需要的话,我们甚至可以将其装配到一个Class类型的bean属性中。但是T()云算符真正的价值在于他能够访问目标类型的静态方法和常量。
如下这个样例会计算得到一个0到1之间的随机数
T(java.lang.Math).random()
SpEL运算符
运算符类型 | 运算符 |
---|---|
算术运算 | +,-,*,/,%,^ |
比较运算 | <,>,==,<=,>=,lt,gt,eq,le,ge |
逻辑运算 | and,or,not,或 |
条件运算 | ?:(ternary),?:(Elvis) |
正则表达式 | matchs |
作为使用上述表达式的一个简单样例,我们来看一下下面这个SpEl表达式:
#{2 * T(java.lang.Math).PI * circle.radius}
这不仅是一个SpEL中乘法运算符(*)的绝佳举例,他也为你展现了如何将简单的表达式组合为更复杂的表达式。在这里PI的值乘以2,然后再乘以radius属性的值,这个属性来源于ID为circle的bean。实际上,他计算了circle bean的所定义圆的周长。
类似的,你还可以在表达式中使用乘方运算符(^)来计算圆的面积
#{T(java.lang.Math).Pi * circle.radius ^ 2}
“^”是用于乘方计算的运算符。