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


    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();
        }
    }
    
    • 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

    当然也可以

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

    实例应用

    赋值

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

    Inventor inventor = new Inventor();
    EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
    
    parser.parseExpression("name").setValue(context, inventor, "Aleksandar Seovic");
    
    • 1
    • 2
    • 3
    • 4

    文字表达

    支持的文字表达式类型是字符串、数值(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();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

    属性访问

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    数组访问

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

        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);
    
    • 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

    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");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    内联列表

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

    List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
    
    List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);
    
    • 1
    • 2
    • 3

    内联map

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

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

    构造数组

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

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

    方法

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

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

    运算表达式

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

    构造器

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

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

    变量

    #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"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里官网的实例有点问题,官网使用了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);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Bean 引用

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

    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    context.setBeanResolver(new MyBeanResolver());
    
    Object bean = parser.parseExpression("@something").getValue(context);
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    context.setBeanResolver(new MyBeanResolver());
    
    Object bean = parser.parseExpression("&foo").getValue(context);
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    优维EasyOps,打造新一代运维新方式
    【无标题】
    「网页开发|前端开发|Vue」04 快速掌握开发网站需要的Vue基础知识
    Elasticsearch:自定义应用程序的日志记录 - Elastic Common Schema
    专家级数据恢复:UFS Explorer Professional Recovery Crack
    07 MyBatis之高级映射 + 懒加载(延迟加载)+缓存
    tomcat的优化
    Mysql JSON对象和JSON数组查询
    【Qt图书管理系统】1.项目设计与需求分析
    高科技电子行业采购供应链管理
  • 原文地址:https://blog.csdn.net/qq_51553982/article/details/126793597