Spring核心——SPEL Bean定义中的表达式、实例应用

181 篇文章 3 订阅
24 篇文章 2 订阅

Bean 定义中的表达式

我们可以使用带有基于 XML 或基于注释的配置元数据的 SpEL 表达式来定义 BeanDefinition 实例。 在这两种情况下,定义表达式的语法都采用 #{ <表达式字符串> } 的形式。
这里我们只研究注解形式

注解形式配置

要指定默认值,您可以将 @Value 注释放在字段、方法以及方法或构造函数参数上。

以下示例设置字段的默认值:

@Component
public class BeanAnnoTest {
    @Value("#{systemProperties['user.name']}")
    private String name;

    public void setName(String name) {
       this.name = name;
    }

    public String getName() {
        return this.name;
    }
}


@RestController
public class TestController {
   @Autowired
   private BeanAnnoTest bean;

    @GetMapping("/test")
    public  String test(){
        System.out.println(bean.getName());
        return bean.getName();
    }
}

当然也可以

	@Value("#{systemProperties['user.name']}")
    public void setName(String name) {
       this.name = name;
    }
@AutoWired
    public void setName(@Value("#{systemProperties['user.name']}")String name) {
       this.name = name;
    }

实例应用

赋值

使用setValue()方法
参数1:EvaluationContext
参数2:对象实例
参数3:值

Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();

parser.parseExpression("name").setValue(context, inventor, "Aleksandar Seovic");

文字表达

支持的文字表达式类型是字符串、数值(int、real、hex)、boolean 和 null。 字符串由单引号分隔。 要将单引号本身放在字符串中,请使用两个单引号字符。
通常,不会像这样孤立地使用,而是作为更复杂表达式的一部分使用——例如,在逻辑比较运算符的一侧使用文字

数字支持使用负号、指数表示法和小数点。 默认情况下,使用 Double.parseDouble() 解析实数。

ExpressionParser parser = new SpelExpressionParser();

String str = (String) parser.parseExpression("'Hello World'").getValue();

double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();

int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();

boolean trueValue = (Boolean) parser.parseExpression("true").getValue();

Object nullValue = parser.parseExpression("null").getValue();

属性、数组、列表、映射和索引器

属性访问

public class Context {
    public int year;
    public String city;

    public Context() {
    }

    public Context(int year, String city) {
        this.year = year;
        this.city = city;
    }
}


        final Context context = new Context();

        final SpelExpressionParser parser = new SpelExpressionParser();

        int year = (Integer) parser.parseExpression("year + 1900").getValue(context);

        String city = (String) parser.parseExpression("city='shanghai'").getValue(context);
        System.out.println(year);
        System.out.println(city);
        int value = (Integer)parser.parseExpression("getYear()").getValue(context);

数组访问

使用[]形式确定索引进行访问

    class tesla {
        public List<String> list = new ArrayList<>();
    }

    class inner{
        public String name;
    }

        final tesla la = new tesla();
        la.list.add("a1");
        la.list.add("a2");
        la.list.add("a3");
        la.list.add("a4");


        ExpressionParser parser = new SpelExpressionParser();
        EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

        String invention = parser.parseExpression("list[3]").getValue(
                context, la, String.class);
        System.out.println(invention);

        final outter outter = new outter();
        final inner inner = new inner();
        inner.name = "zhangsan";
        outter.member.add(inner);

        String name = parser.parseExpression("member[0].name").getValue(
                context, outter, String.class);
        System.out.println(name);

map访问

通过在括号内指定文字键值来获取映射的内容

Inventor pupin = parser.parseExpression("officers['president']").getValue(
        societyContext, Inventor.class);

String city = parser.parseExpression("officers['president'].placeOfBirth.city").getValue(
        societyContext, String.class);

parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
        societyContext, "Croatia");

内联列表

使用 {} 表示法直接在表达式中表达列表。
{} 本身意味着一个空列表。 出于性能原因,如果列表本身完全由固定文字组成,则会创建一个常量列表来表示表达式(而不是在每次评估时构建一个新列表)。

List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);

List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);

内联map

您还可以使用 {key:value} 表示法直接在表达式中表示映射

Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);

构造数组

直接通过new关键字构造,这和Java本身是一样的!

int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);


int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);

方法

其中getValue()包含两个参数
参数1:对象实例
参数2:方法返回值类型

boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
        societyContext, Boolean.class);

运算表达式

支持等值比较,大小比较,三元表达式,正则表达式,and(&&),or(||),not(!)

构造器

通过new关键字可以直接调用类的构造器进行构造

Inventor einstein = p.parseExpression(
        "new Custom('zhangsan',18)")
        .getValue(Inventor.class);

变量

#this :变量始终被定义并引用当前评估对象(针对哪些非限定引用被解析)
#root: 变量始终被定义并引用根上下文对象
尽管 #this 可能会随着表达式的组件的计算而变化,但 #root 始终指的是根。

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"

这里官网的实例有点问题,官网使用了forReadOnlyDataAccess()方法,但实际上根本没有这个方法,而是应该使用forReadWriteDataBinding().build()
以下示例显示如何使用 #this 和 #root 变量:

        List<Integer> primes = new ArrayList<Integer>();
        primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
        
        ExpressionParser parser = new SpelExpressionParser();
        EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
        context.setVariable("primes", primes);
        
        List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
                "#primes.?[#this>10]").getValue(context);

        System.out.println(primesGreaterThanTen);
        for (Integer integer : primesGreaterThanTen) {
            System.out.println(integer);
        }

Bean 引用

如果评估上下文已经配置了 bean 解析器,您可以使用 @ 符号从表达式中查找 bean。 以下示例显示了如何执行此操作:

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());

Object bean = parser.parseExpression("@something").getValue(context);

要访问工厂 bean 本身,您应该在 bean 名称前加上 & 符号。 以下示例显示了如何执行此操作:

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());

Object bean = parser.parseExpression("&foo").getValue(context);
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值