spring注入外部的值(Environment)

2,162 阅读4分钟

注入外部值

在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}

“^”是用于乘方计算的运算符。