之前讨论的依赖注入,主要关注将一个bean引用注入到另一个bean的属性或构造器参数中。
依赖注入还有另外一方面:将值注入到bean的属性或构造器参数中。
当然可以使用之前说过的硬编码,但是我们这里希望这些值在运行时确定。
Spring提供2种运行时求值方式:属性占位符(Property placeholder)、Spring表达式语言(SpEL)
1、注入外部的值
1.1、用法
使用@PropertySource注解和Environment
@Configuration @PropertySource("classpath:/com/soundsystem/app.properties") public class EnvironmentConfig { @Autowired Environment env; @Bean public BlankDisc blankDisc() { return new BlankDisc( env.getProperty("disc.title"), env.getProperty("disc.artist")); } }
通过@PropertySource注解引用一个名为app.properties的文件,文件内容如下
disc.title=Sgt. Peppers Lonely Hearts Club Band
disc.artist=The Beatles
然后通过Spring的Environment,使用getProperty()方法,进行检索属性。
1.2、深入Spring的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()方法如果没有找到对应的属性,会返回null值
getRequiredProperty()方法,如果没有找到属性,会抛出IllegalStateException异常
containsProperty()方法:检查某个属性是否存在
getPropertyAsClass()方法:将属性解析为类
检查profile的激活状态
String[] getActiveProfiles():返回激活profile名称的数组;
String[] getDefaultProfiles():返回默认profile名称的数组;
boolean acceptsProfiles(String... profiles):如果environment支持给定profile的话,返回true
1.3、解析属性占位符“${...}”以及注解@Value
使用Environment检索属性很方便,Spring同时也提供了占位符装配属性的方法
a、配置PropertyPlaceholderConfigurer bean或PropertySourcesPlaceholderConfigurer bean(Spring3.1开始推荐用这个) ,这个bean可以基于Spring Environment以及其属性源来解析占位符
Java配置
@Bean public static PropertySourcesPlaceholderConfigurer placeholderConfigurer(){ return new PropertySourcesPlaceholderConfigurer(); }
XML配置,引用Spring context命名空间中的<context:property-placeholder />即可自动生成PropertySourcesPlaceholderConfigurer 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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-beans.xsd"> <context:property-placeholder /> </beans>
b、注入
Java注入
public BlandKisc( @Value("${disc.title}") String title, @Value("${disc.artist}") String artist){ this.title = title; this.artist = artist; }
XML注入
<bean id="sgtPeppers" class="soundsystem.BlandDisc" c:_title="${disc.title}" c:_artist="${disc.artist}" />
2、使用Spring表达式语言进行装配
Spring 3引入了Spring表达式语言(Spring Expression Language,SpEL),能够强大和简洁地把值装配到bean属性和构造器参数中。
SpEL的一些特性:
·使用bean的ID引用bean;
·调用方法和访问对象的属性;
·对值进行算术、关系和逻辑运算;
·正则表达式匹配;
·集合操作;
2.1、表示字面值
#{1}//整型 #{3.14159}//浮点数 #{9.87E4}//科学计数法 #{'Hello'}//String类型字面值 #{false}//Boolean类型
2.2、引用bean、属性和方法
#{sgtPeppers}//引用ID为sgtPeppers的bean #{sgtPeppers.artist}//引用bean的属性 #{sgtPeppers.selectArtist()}//调用bean的方法 #{sgtPeppers.selectArtist().toUpperCase()}//调用bean的方法的值的方法,例如方法值是String类型,则可以调用String对象的toUpperCase方法 #{sgtPeppers.selectArtist()?.toUpperCase()}//类型安全的运算符“?.”,当值为null时返回null,否则猜执行toUpperCase方法
2.3、表达式中使用类型
主要作用是调用类的静态方法和变量。使用T()运算符,获得Class对象。
#{T(java.lang.Math)}//得到一个class对象 #{T(java.lang.Math).PI}//类的常量 #{T(java.lang.Math).random()}//类的静态方法
2.4、SpEL运算符
用于在SpEL表达式上做运算
#{2 * T(java.lang.Math).PI * circle.radius}//计算周长 #{T(java.lang.Math).PI * circle.radius ^ 2}//计算面积 #{disc.title + ' by ' + disc.artist}//拼接字符串 #{counter.total == 100}//比较运算符 结果为布尔值 #{counter.total eq 100}//比较运算符 结果为布尔值 #{scoreboard.score ? 1000 ? "Winner!" : "Loser"}//三元运算符 #{disc.title ?: 'Rattle and Hum'}//Elvis运算符(Elvis是猫王的名字,?:符号像猫王的头发),判断是否为null,是null则给默认值
2.5、计算正则表达式
使用matches运算符,返回Boolean类型值
#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.com'}//验证有效邮件
2.6、计算集合
#{jukebox.songs[4].title}//songs集合第5个元素的title属性 #{'this is a test'[3]}//String中的一个字符 #{jukebox.songs.?[artist eq 'Jay']}//使用查询运算符(.?[])过滤子集 #{jukebox.songs.^[artist eq 'Jay']}//使用第一个匹配符(.^[])找到第一个匹配的项 #{jukebox.songs.$[artist eq 'Jay']}//使用最后一个匹配符(.$[])找到最后一个匹配的项 #{jukebox.songs.![title]}//投影运算符(.![])选择属性投影到一个新的集合