SpEL全称Spring Expression Language,是一种强大的表达式语言,支持在运行时查询和操纵对象图。在SpEL诞生以前就已经有多种表达式语言了,如OGNL,MVEL,JBoss EL等等,那么Spring团队为什么还要发明SpEL呢?SpEL的目标是对Spring所有作品集提供良好的表达式计算支持。另外SpEL虽然对Spring的项目集提供良好的支持,但并不依赖于Spring运行,SpEL可以独立运行。
使用
在Spring中使用SpEL只需要编写SpEL表达式字符串就可以了,因为Spring已经为我们集成好了SpEL,如果是单独使用SpEL需要编写一些启动SpEL的代码,然后才能进行表达式计算,启动类代码中主要使用ExpressionParser,SpelExpressionParser,EvaluationContext,SimpleEvaluationContext,StandardEvaluationContext几个类,作为模板代码,以下如果不特殊说明,所有的表达式计算均在该模板代码中进行计算,其中parser就是指SpelExpressionParser,而context是SimpleEvaluationContext或者StandardEvaluationContext。
1
2
3
4
5
6
7
8
9
| ExpressionParser parser = new SpelExpressionParser();
Inventor inventor = new Inventor("tesla", new Date(), "Serbian");
inventor.setPlaceOfBirth(new PlaceOfBirth("AAA", "CCC"));
//EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().withRootObject(inventor).build();
StandardEvaluationContext context = new StandardEvaluationContext(inventor);
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);
System.out.println(year);
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);
System.out.println(city);
|
例子中使用的类如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
| package org.spring.samples.spel.inventor;
import java.util.Date;
import java.util.GregorianCalendar;
public class Inventor {
private String name;
private String nationality;
private String[] inventions;
private Date birthdate;
private PlaceOfBirth placeOfBirth;
public Inventor(String name, String nationality) {
GregorianCalendar c= new GregorianCalendar();
this.name = name;
this.nationality = nationality;
this.birthdate = c.getTime();
}
public Inventor(String name, Date birthdate, String nationality) {
this.name = name;
this.nationality = nationality;
this.birthdate = birthdate;
}
public Inventor() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public Date getBirthdate() {
return birthdate;
}
public void setBirthdate(Date birthdate) {
this.birthdate = birthdate;
}
public PlaceOfBirth getPlaceOfBirth() {
return placeOfBirth;
}
public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) {
this.placeOfBirth = placeOfBirth;
}
public void setInventions(String[] inventions) {
this.inventions = inventions;
}
public String[] getInventions() {
return inventions;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| package org.spring.samples.spel.inventor;
public class PlaceOfBirth {
private String city;
private String country;
public PlaceOfBirth(String city) {
this.city=city;
}
public PlaceOfBirth(String city, String country) {
this(city);
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String s) {
this.city = s;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| package org.spring.samples.spel.inventor;
import java.util.*;
public class Society {
private String name;
public static String Advisors = "advisors";
public static String President = "president";
private List<Inventor> members = new ArrayList<Inventor>();
private Map officers = new HashMap();
public List getMembers() {
return members;
}
public Map getOfficers() {
return officers;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMember(String name) {
for (Inventor inventor : members) {
if (inventor.getName().equals(name)) {
return true;
}
}
return false;
}
}
|
SpEL语法
字面量表达式
spel字面量表达式支持字符串,数字(整数,实数,16进制数),布尔,以及null。字符串使用单引号包裹。如果字符串中包含单引号',那么单引号需要使用两个单引号''来转义。
1
2
3
4
5
6
7
8
9
10
11
12
13
| ExpressionParser parser = new SpelExpressionParser();
// evals to "Hello World"
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();
double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
// evals to 2147483647
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
Object nullValue = parser.parseExpression("null").getValue();
|
属性、数组、列表、Maps和索引表达式
属性导航语法使用.,支持多级导航。
下面例子中使用的context的根对象为Inventor对象,在测试时需要自己new一个对象,并设置为context的根对象。
注意属性的首字母是不区分大小写的
1
2
3
4
| // evals to 1856
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);
|
数组和列表的元素使用方括号[]记法访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// Inventions Array
// evaluates to "Induction motor"
String invention = parser.parseExpression("inventions[3]").getValue(
context, tesla, String.class);
// Members List
// evaluates to "Nikola Tesla"
String name = parser.parseExpression("Members[0].Name").getValue(
context, ieee, String.class);
// List and Array navigation
// evaluates to "Wireless communication"
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(
context, ieee, String.class);
|
Maps的条目检索也使用[]记法,不同于数组和列表的索引,这里的索引是字符串
1
2
3
4
5
6
7
8
9
10
11
12
| // Officer's Dictionary
Inventor pupin = parser.parseExpression("Officers['president']").getValue(
societyContext, Inventor.class);
// evaluates to "Idvor"
String city = parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(
societyContext, String.class);
// setting values
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(
societyContext, "Croatia");
|
内联列表达式
spel可以使用{}表示列表字面量
{}本身表示空列表
1
2
3
4
| // evaluates to a Java list containing the four numbers
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);
|
内联Maps表达式
spel中可以使用{:}记法表示Map字面量
{:}本身表示空Map
1
2
3
4
| // evaluates to a Java map containing the two entries
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);
|
创建数组表达式
spel中可以使用熟悉的java语法创建数组,并且可以提供初始化器在创建时填充数组。当前spel还不支持多维数组的初始化器。
1
2
3
4
5
6
7
| int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
// Array with initializer
int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);
// Multi dimensional array
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
|
方法调用表达式
spel中可以使用java的语法调用方法。可以调用字面量的方法。支持变量参数。
1
2
3
4
5
6
| // string literal, evaluates to "bc"
String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
// evaluates to true
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
societyContext, Boolean.class);
|
运算符表达式
spel支持4种运算符,分别是关系运算符,逻辑运算符,算术运算符,赋值运算符。这些运算符和java中的运算符一致,只是有些运算符提供了别名。
关系运算符包括等于、不等于、小于、小于等于、大于、大于等于。
关系运算符
1
2
3
4
5
6
7
8
| // evaluates to true
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
// evaluates to false
boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);
// evaluates to true
boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
|
除了标准的关系运算符外,spel还支持instanceof和基于正则表达式匹配语法matches
1
2
3
4
5
6
7
8
9
10
11
| // evaluates to false
boolean falseValue = parser.parseExpression(
"'xyz' instanceof T(Integer)").getValue(Boolean.class);
// evaluates to true
boolean trueValue = parser.parseExpression(
"'5.00' matches '^-?\\d+(\\.\\d{2})?#39;").getValue(Boolean.class);
//evaluates to false
boolean falseValue = parser.parseExpression(
"'5.0067' matches '^-?\\d+(\\.\\d{2})?#39;").getValue(Boolean.class);
|
值得注意的是spel表达式中在计算时原始类型会立即转化成包裹器类型,所以1 instanceof T(int)计算结果为false,而1 instanceof T(Integer)计算结果为true
有时候spel表达式会内嵌到文档中去,如xml文档,而在这些文档中,运算符符号会有特殊的含义,为了避免产生问题,有些运算符符号会有一个对应的文本表示。并且文本表示是大小写不敏感的。
- lt (<)
- gt (>)
- le (<=)
- ge (>=)
- eq (==)
- ne (!=)
- div (/)
- mod (%)
- not (!)
逻辑运算符
spel支持3种逻辑运算符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| // -- AND --
// evaluates to false
boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);
// evaluates to true
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
// -- OR --
// evaluates to true
boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class);
// evaluates to true
String expression = "isMember('Nikola Tesla') or isMember('Albert Einstein')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
// -- NOT --
// evaluates to false
boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class);
// -- AND and NOT --
String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
|
算术运算符
spel中加法运算可以作用到数字和字符串的运算,而减、乘、除只能作用到数字上。求模运算和指数运算也只能作用到数字上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| // Addition
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
String testString = parser.parseExpression(
"'test' + ' ' + 'string'").getValue(String.class); // 'test string'
// Subtraction
int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4
double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000
// Multiplication
int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0
// Division
int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2
double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0
// Modulus
int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3
int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1
// Operator precedence
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21
|
赋值运算符
spel中可以为属性赋值,有两种方式,一种是使用赋值运算符配合getValue方法调用,另外一种是直接通过setValue方法调用。
1
2
3
4
5
6
7
8
| Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
parser.parseExpression("Name").setValue(context, inventor, "Aleksandar Seovic");
// alternatively
String aleks = parser.parseExpression(
"Name = 'Aleksandar Seovic'").getValue(context, inventor, String.class);
|
类型表达式
在spel中可以使用T运算符指定一个java.lang.Class类型的实例。静态方法调用也使用该运算符。指定类型时除了java.lang包中的类可以使用简单名称外,其余类均需要使用全限定名。
1
2
3
4
5
6
7
| Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
boolean trueValue = parser.parseExpression(
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
.getValue(Boolean.class);
|
构造器调用表达式
使用java标准的new语法调用构造器创建一个类的实例,注意类名称需要使用全限定名。
1
2
3
4
5
6
7
8
| Inventor einstein = p.parseExpression(
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
.getValue(Inventor.class);
//create new inventor instance within add method of List
p.parseExpression(
"Members.add(new org.spring.samples.spel.inventor.Inventor(
'Albert Einstein', 'German'))").getValue(societyContext);
|
变量
变量是通过EvaluationContext接口的setVariable方法调用创建的,在表达式中可以使用#variableName语法引用变量。
变量名称只能是下列一个或多个字符的组合
1
2
3
4
5
6
7
| Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
context.setVariable("newName", "Mike Tesla");
parser.parseExpression("Name = #newName").getValue(context, tesla);
System.out.println(tesla.getName()) // "Mike Tesla"
|
特殊的#this和#root变量
#this变量在每一步计算时总是有定义的,并且值为当前计算对象。#root变量也总是有定义的,表示根对象。也就是说#this在每一步计算表达式时都可能会发生变化,而#root总是表示根对象。
下面的例子中使用了集合筛选语法.?[筛选表达式],如果看不明白可以先阅读集合筛选
1
2
3
4
5
6
7
8
9
10
11
12
13
| // create an array of integers
List<Integer> primes = new ArrayList<Integer>();
primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
// create parser and set variable 'primes' as the array of integers
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataAccess();
context.setVariable("primes", primes);
// all prime numbers > 10 from the list (using selection ?{...})
// evaluates to [11, 13, 17]
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
"#primes.?[#this>10]").getValue(context);
|
函数
可以通过EvaluationContext的setVariable方法调用来创建自定义函数,然后在spel表达式中通过变量引用语法类似的方式调用自定义函数
1
2
3
4
| Method method = ...;
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("myFunction", method);
|
下面创建一个工具方法来把一个字符串逆序产生一个新的字符串。
1
2
3
4
5
6
7
8
9
10
| public abstract class StringUtils {
public static String reverseString(String input) {
StringBuilder backwards = new StringBuilder(input.length());
for (int i = 0; i < input.length(); i++) {
backwards.append(input.charAt(input.length() - 1 - i));
}
return backwards.toString();
}
}
|
一个完整的函数注册和使用的例子
1
2
3
4
5
6
7
8
| ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("reverseString",
StringUtils.class.getDeclaredMethod("reverseString", String.class));
String helloWorldReversed = parser.parseExpression(
"#reverseString('hello')").getValue(context, String.class);
|
Bean引用
如果计算上下文EvaluationContext已经配置了一个bean解析器,可以在spel表达式中使用@beanName语法来查找bean
1
2
3
4
5
6
| ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());
// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
Object bean = parser.parseExpression("@something").getValue(context);
|
如果是访问bean对应的factory bean,可以使用&beanName语法。
1
2
3
4
5
6
| ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
Object bean = parser.parseExpression("&foo").getValue(context);
|
三元运算符
可以使用三元运算符在表达式中执行if-then-else的条件判断逻辑。
语法为java标准的三元运算符? :
1
2
| String falseString = parser.parseExpression(
"false ? 'trueExp' : 'falseExp'").getValue(String.class);
|
执行结果为'falseExp'
下面是一个更为现实的例子
1
2
3
4
5
6
7
8
9
| parser.parseExpression("Name").setValue(societyContext, "IEEE");
societyContext.setVariable("queryName", "Nikola Tesla");
expression = "isMember(#queryName)? #queryName + ' is a member of the ' " +
"+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'";
String queryResultString = parser.parseExpression(expression)
.getValue(societyContext, String.class);
// queryResultString = "Nikola Tesla is a member of the IEEE Society"
|
Elvis运算符
Elvis运算符借鉴于groovy语言,是java三元运算符的简写形式。通常在使用三元运算符时,一个变量要重复两次,如下面所示
1
2
| String name = "Elvis Presley";
String displayName = (name != null ? name : "Unknown");
|
为了简化这种情形,可以使用Elvis运算符来简写
1
2
3
4
| ExpressionParser parser = new SpelExpressionParser();
String name = parser.parseExpression("name?:'Unknown'").getValue(new Inventor(), String.class);
System.out.println(name); // 'Unknown'
|
可以使用Elvis运算符为spel表达式提供缺省值,下面是一个在@value注解中使用Elvis运算符的例子
1
| @Value("#{systemProperties['pop3.port'] ?: 25}")
|
上面的例子中将会注入一个系统属性pop3.port,如果没有定义将会使用25
安全导航运算符
安全导航运算符也是借鉴于groovy语言,是为了避免在访问一个对象的属性时,产生空指针异常。使用安全导航在访问属性所属的对象为null时,会返回null而不会产生NullPointerException
1
2
3
4
5
6
7
8
9
10
11
12
| ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city); // Smiljan
tesla.setPlaceOfBirth(null);
city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city); // null - does not throw NullPointerException!!!
|
集合筛选
集合筛选用于筛选原始集合中符合条件的元素,产生一个原始集合的子集合。
语法为.?[筛选表达式]
1
2
| List<Inventor> list = (List<Inventor>) parser.parseExpression(
"Members.?[Nationality == 'Serbian']").getValue(societyContext);
|
集合筛选可以应用于List和Map。对于List,筛选条件的当前计算对象是List中的每一个元素;而对于Map,筛选条件的当前计算对象是Map的条目,类型为Map.Entry,每一个条目的key和value属性可以在筛选表达式中访问。
1
| Map newMap = parser.parseExpression("map.?[value<27]").getValue();
|
除了返回所有符合条件的元素外,还可以检索第一个或者最后一个符合条件的元素。
获取第一个符合筛选表达式的元素的语法是.^[筛选表达式]
获取最后一个符合条件的元素的语法是.$[筛选表达式]
集合投影
集合投影或者叫做集合映射,是通过原始集合上计算投影表达式,将原始集合中的每一个元素产生一个新的元素,新的元素可能与原始集合中的元素类型相同,也可能不同。
集合投影的语法为.![投影表达式]
下面的例子中获取所有Inventor的出生城市,原始集合为List<Inventor>,而投影后的集合为List<String>
1
2
| // returns ['Smiljan', 'Idvor' ]
List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]");
|
也可以对Map进行集合投影,投影表达式的计算上下文对应为Map中的每一个条目,类型为Map.Entry,投影的结果是一个List。
表达式模板
表达式模板允许在spel表达式中混合字面量文本和一个或多个计算块,计算块是由我们定义的前缀和后缀字符串包裹的spel表达式。通常使用默认常用的#{}作为计算块的包裹字符串。
1
2
3
4
5
| String randomPhrase = parser.parseExpression(
"random number is #{T(java.lang.Math).random()}",
new TemplateParserContext()).getValue(String.class);
// evaluates to "random number is 0.7038186818312008"
|
类似于字符串内插,上面例子中的random number is 作为字面量文本和#{}中包裹的表达式计算结果相连接。
注意parseExpression方法的第二个参数是一个ParserContext接口类型的参数,该接口会影响表达式解析时对表达式模板的计算。
下面是TemplateParserContext的定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public class TemplateParserContext implements ParserContext {
public String getExpressionPrefix() {
return "#{";
}
public String getExpressionSuffix() {
return "}";
}
public boolean isTemplate() {
return true;
}
}
|
注意
- 由于SpEL表达式本身使用字符串表示,所以SpEL中字符串字面量使用’’(单引号)表示。
- SpEL中属性访问时,属性的首字母是不区分大小写的,也就是说属性name和Name表示同一个属性
- 在SpEL中访问变量时使用#var的形式,在Spring中所有ApplicationContext中定义的bean都是预定义的变量,变量名称为bean名称,包括标准的环境抽象environment(org.springframework.core.env.Environment)、jvm系统属性systemProperties(Map<String, Object>)、系统环境变量systemEnvironment(Map<String, Object>),但是在访问这些变量时不需要使用#var语法,只需要使用var就可以了
SpEL表达式在Bean定义中的应用
这里的bean定义使用java注解方式配置
SpEL表达式在bean定义中的应用主要是使用@Value注解的方式对bean的属性,方法,方法参数以及构造器参数进行依赖注入
为属性注入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class FieldValueTestBean {
@Value("#{ systemProperties['user.region'] }")
private String defaultLocale;
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
}
|
通过setter方法注入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class PropertyValueTestBean {
private String defaultLocale;
@Value("#{ systemProperties['user.region'] }")
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
}
|
在自动装配方法或构造器上注入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| public class SimpleMovieLister {
private MovieFinder movieFinder;
private String defaultLocale;
@Autowired
public void configure(MovieFinder movieFinder,
@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
this.movieFinder = movieFinder;
this.defaultLocale = defaultLocale;
}
// ...
}
public class MovieRecommender {
private String defaultLocale;
private CustomerPreferenceDao customerPreferenceDao;
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
@Value("#{systemProperties['user.country']}") String defaultLocale) {
this.customerPreferenceDao = customerPreferenceDao;
this.defaultLocale = defaultLocale;
}
// ...
}
|