• Spring中表达式语言spring-expression简单使用


    前言

    Spring Expression Language(简称 SpEL)是一个支持查询和操作运行时对象导航图功能的强大的表达式语言,
    它的语法类似于传统 EL(如jsp中的EL表达式),但提供额外的功能,最出色的就是函数调用和简单字符串的模板函数。

    SpEL 作为Spring框架的基础,但并不依赖于Spring容器,可以独立使用。

    简单使用

    引入maven依赖

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.1.RELEASE</version>
    </dependency>
    

    简单字面量

    支持字符串,日期,数值(整型,浮点型,十六进制),布尔等类型

    //创建表达式解析器
    ExpressionParser expressionParser = new SpelExpressionParser();
    //解析表达式并获取结果
    System.out.println(expressionParser.parseExpression("'hello'").getValue());
    System.out.println(expressionParser.parseExpression("123").getValue());
    System.out.println(expressionParser.parseExpression("12.34").getValue());
    System.out.println(expressionParser.parseExpression("10e2").getValue());
    System.out.println(expressionParser.parseExpression("true").getValue());
    System.out.println(expressionParser.parseExpression("new java.util.Date()").getValue());
    

    输出结果为

    hello
    123
    12.34
    1000.0
    true
    Sat Sep 25 19:39:38 CST 2021
    

    变量引用

    通过#'变量名'的方式来使用变量

    //创建表达式解析器
    ExpressionParser expressionParser = new SpelExpressionParser();
    //创建数据上下文
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
    //设置变量
    evaluationContext.setVariable("a", 12);
    evaluationContext.setVariable("b", 34);
    evaluationContext.setVariable("c", 56);
    //解析表达式
    System.out.println(expressionParser.parseExpression("#a+#b-#c").getValue(evaluationContext));
    

    输出为

    -10
    

    对象的属性和方法

    定义一个普通bean

    public class User {
    
      private String name;
    
      public User(String name) {
        this.name = name;
      }
    
      public void setName(String name) {
        this.name = name;
      }
    
      public String getName() {
        return name;
      }
    }
    

    通过对象.属性的方式来引用

    //创建表达式解析器
    ExpressionParser expressionParser = new SpelExpressionParser();
    //创建数据上下文
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
    evaluationContext.setVariable("user", new User("lisi"));
    System.out.println(expressionParser.parseExpression("#user.name").getValue(evaluationContext));
    System.out.println(expressionParser.parseExpression("#user.getName()").getValue(evaluationContext));
    

    输出为

    lisi
    lisi
    

    数组,集合,map

    //创建表达式解析器
    ExpressionParser expressionParser = new SpelExpressionParser();
    //创建数据上下文
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
    //设置数组变量
    evaluationContext.setVariable("users", new User[]{new User("Tom")});
    //设置集合变量
    evaluationContext.setVariable("userList", Collections.singletonList(new User("Mary")));
    //设置map变量
    evaluationContext.setVariable("userMap", Collections.singletonMap("u123", new User("u123")));
    System.out.println(expressionParser.parseExpression("#users[0].name").getValue(evaluationContext));
    System.out.println(expressionParser.parseExpression("#userList[0].name").getValue(evaluationContext));
    System.out.println(expressionParser.parseExpression("#userMap['u123'].name").getValue(evaluationContext));
    

    输出为

    Tom
    Mary
    u123
    

    普通方法调用

    和在Java中使用没有区别

    //创建表达式解析器
    ExpressionParser expressionParser = new SpelExpressionParser();
    System.out.println(expressionParser.parseExpression("'hello'.substring(2)").getValue());
    

    输出为

    llo
    

    操作符

    支持关系操作符(大于 小于 等于),逻辑操作符(and or not),算数操作符(加减乘除)

    //创建表达式解析器
    ExpressionParser expressionParser = new SpelExpressionParser();
    System.out.println(expressionParser.parseExpression("1 < 4").getValue());
    System.out.println(expressionParser.parseExpression("1 < 4 and 5 > 9 ").getValue());
    System.out.println(expressionParser.parseExpression("1 + 3 - 5").getValue());
    

    引用IOC容器中的bean

    定义bean的配置文件

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class BeanConfig {
    
      @Bean
      public User user() {
        return new User("lisi");
      }
    }
    

    默认支持#{}的格式来引用bean

    //创建表达式解析器
    ExpressionParser expressionParser = new SpelExpressionParser();
    //创建数据上下文
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
    //创建IOC容器上下文
    ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
    //创建bean表达式上下文
    BeanExpressionContext beanExpressionContext = new BeanExpressionContext((ConfigurableBeanFactory) context.getAutowireCapableBeanFactory(), null);
    evaluationContext.setRootObject(beanExpressionContext);
    //添加属性访问器 从IOC容器中获取bean
    evaluationContext.addPropertyAccessor(new BeanExpressionContextAccessor());
    System.out.println(expressionParser.parseExpression("#{user.name}", new TemplateParserContext()).getValue(evaluationContext));
    

    输出为

    lisi
    

    @Value注解

    我们在项目中很多地方都会用到@Value注解

    @Value("${name}")
    private String name;
    
    @Value("#{person.name}")
    private String personName;
    

    解析@Value注解的过程就会使用到SpEL

    public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
            @Nullable
    	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
    			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    
    		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    		try {
    			Object shortcut = descriptor.resolveShortcut(this);
    			if (shortcut != null) {
    				return shortcut;
    			}
    
    			Class<?> type = descriptor.getDependencyType();
    			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    			if (value != null) {
    				//字符串类型就表示是@Value注解注入
    				if (value instanceof String) {
    					// 使用StringValueResolver处理${}占位符
    					String strVal = resolveEmbeddedValue((String) value);
    					BeanDefinition bd = (beanName != null && containsBean(beanName) ?
    							getMergedBeanDefinition(beanName) : null);
    					//处理bean表达式,#{}这种格式
    					value = evaluateBeanDefinitionString(strVal, bd);
    				}
    				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
    				try {
    					return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
    				}
    				catch (UnsupportedOperationException ex) {
    					// A custom TypeConverter which does not support TypeDescriptor resolution...
    					return (descriptor.getField() != null ?
    							converter.convertIfNecessary(value, type, descriptor.getField()) :
    							converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
    				}
    			}
    
    		...
    		...
    	}
    
            @Nullable
    	protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
    		if (this.beanExpressionResolver == null) {
    			return value;
    		}
    
    		Scope scope = null;
    		if (beanDefinition != null) {
    			String scopeName = beanDefinition.getScope();
    			if (scopeName != null) {
    				scope = getRegisteredScope(scopeName);
    			}
    		}
    		return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
    	}
    }
    

    默认使用的beanExpressionResolver为StandardBeanExpressionResolver。

    参考

    Spring学习总结(四)——表达式语言 Spring Expression Language
    【小家Spring】SpEL你感兴趣的实现原理浅析spring-expression~(SpelExpressionParser、EvaluationContext、rootObject)

  • 相关阅读:
    js设计模式(一)---单例模式
    JavaScript---设计模式总结
    js设计模式---单例模式
    js设计模式---工厂模式
    react学习笔记01
    css常用布局
    js 继承
    vue路由动态加载
    vue 项目总结
    css文字两端对齐
  • 原文地址:https://www.cnblogs.com/strongmore/p/15335622.html
Copyright © 2020-2023  润新知