音标spel发音 (spel配置)

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种逻辑运算符

  • and (&&)
  • or (||)
  • not (!)

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语法引用变量。

变量名称只能是下列一个或多个字符的组合

  • 字母a-z以及A-Z
  • 数字0-9
  • 下划线_
  • 美元符号$

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

注意

  1. 由于SpEL表达式本身使用字符串表示,所以SpEL中字符串字面量使用’’(单引号)表示。
  2. SpEL中属性访问时,属性的首字母是不区分大小写的,也就是说属性name和Name表示同一个属性
  3. 在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;
    }

    // ...
}