一、SpringEL-基础介绍

  1. 什么是SpringEL(SpEL)?Spring3中引入了Spring表达式语言—SpringEL,SpEL是一种强大,简洁的装配Bean的方式SpringEL可以通过运行期间执行的表达式将值装配到我们的属性或构造函数当中SpringEL可以调用JDK中提供的静态常量,获取外部Properties文件中的的配置
  2. 为什么要使用SpringEL?平常通过配置文件或Annotaton注入的Bean,其实都可以称为静态性注入如Bean A中有变量A,它的值需要根据Bean B的B变量为参考,在这场景下静态注入就对这样的处理显得非常无力而Spring3增加的SpringEL就可以完全满足这种需求,而且还可以对不同Bean的字段进行计算再进行赋值,功能非常强大
  3. 如何使用SpringEL?SpringEL从名字来看就能看出和EL是有点关系的,SpringEL的使用和EL表达式的使用非常相似EL表达式在JSP页面更方便地获取后台中的值,而SpringEL就是为了更方便获取Spring容器中的Bean的值EL使用${},而SpringEL使用#{}进行表达式的声明
  4. 两者主要区别$是去找外部配置的参数,将值赋过来#是SpEL表达式,去寻找对应变量的内容也可以直接使用@value("常量")注入不使用EL,这样写法与直接赋值等价
  5. 如果是在Spring中使用可以使用@PropertySource("classpath:my.properties")加载对应配置文件

二、EL表达式-基础使用

# 配置文件
com:codecoord:el:num: 1001name: ellanguage:- java- spring- mysql- linux# 逗号分隔可以注入列表language02: java,spring,mysql,linux
  1. 使用EL注入简单值
/*** 注入简单值,直接注入不使用EL,EL不支持直接指定常量* 直接在EL中指定的常量会当做配置处理,和直接赋值等价*/
@Value("1432516744")
private Integer no;
  1. 注入配置文件属性值
/*** 注入整型属性值*/
@Value("${com.codecoord.el.num}")
private Integer num;
/*** 注入字符属性值*/
@Value("${com.codecoord.el.name}")
private String name;
  1. 注入默认值
/*** 注入字符不存在属性值并指定默认值,默认值使用过冒号分隔 :* 注入常量其实就可以指定一个不存在的配置然后使用默认值,此处skill的值为java*/
@Value("${com.codecoord.el.skill:java}")
private String skill;
  1. 注入列表不支持直接配置文件中数组语法格式注入列表可以识别使用逗号,分隔的配置,spring默认以,分隔
// 错误写法:不支持直接注入yml列表格式语法列表
@Value("${com.codecoord.el.language}")
private List<String> listLanguage;
@Value("${com.codecoord.el.language}")
private String[] strLanguage;/*** 支持,分隔的注入列表*/
@Value("${com.codecoord.el.language02}")
private List<String> listLanguage02;
@Value("${com.codecoord.el.language02}")
private String[] strLanguage02;
  1. 完整参考如下配置文件
server:port: 8888
com:codecoord:el:num: 1001name: ellanguage:- java- spring- mysql- linux# 逗号分隔可以注入列表language02: java,spring,mysql,linux
  • 属性配置类
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.util.List;@Data
@Component
public class ElConfig {/*** 注入简单值,直接注入不使用EL,EL不支持直接指定常量* 直接在EL中指定的常量会当做配置处理,和直接赋值等价*/@Value("1432516744")private Integer no;/*** 注入整型属性值*/@Value("${com.codecoord.el.num}")private Integer num;/*** 注入字符属性值*/@Value("${com.codecoord.el.name}")private String name;/*** 注入字符不存在属性值并指定默认值,默认值使用过冒号分隔 :* 注入常量其实就可以指定一个不存在的配置然后使用默认值,此处skill的值为java*/@Value("${com.codecoord.el.skill:java}")private String skill;/// 不支持直接注入列表/*@Value("${com.codecoord.el.language}")private List<String> listLanguage;@Value("${com.codecoord.el.language}")private String[] strLanguage;*//*** 支持,分隔的注入列表*/@Value("${com.codecoord.el.language02}")private List<String> listLanguage02;@Value("${com.codecoord.el.language02}")private String[] strLanguage02;
}
  • 向controller中注入配置类,然后访问接口测试结果如下
{"no": 1432516744,"num": 1001,"name": "el","skill": "java","listLanguage02": ["java","spring","mysql","linux"],"strLanguage02": ["java","spring","mysql","linux"]
}

三、SpringEL-基础使用

  1. 使用SpEL注入简单值和普通EL注入使用基本一致
  2. SpEl注入map配置文件中需要使用双引号括起来,否则将会注入失败,key为单引号
# SpEl
spEl:mapInject: "{'name': 'SpEl', 'website': 'http://www.codeocord.com'}"
  • java类中先使用${spEl.mapInject}注入字符串值,#{}会解析字符串的值转为map
@Value("#{${spEl.mapInject}}")
private Map<String, String> mapInject;
  1. SpEl注入list除了可以通过EL注入listI外,也可以使用#{${}.split('分隔符')}的方式注入List配置文件中例如使用#分隔
spEl:listInject: "44#11#99#100"
  • java类中先使用${spEl.listInject}注入字符串值,内容使用单引号括起来,然后对字符串使用split方法分隔
  • 提示:避免为空情况,可以给一个默认值空串
@Value("#{'${spEl.listInject:}'.split('#')}")private List<String> listInject;
  1. 动态注入上述注入都是静态注入,SpEl支持从Spring容器中注入信息,称为动态注入。动态注入类如下
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Component
@Data
public class SpElConstant {private String name = "SpElConstant-name";private String nickname = "tianxin";private int num = 100;private List<String> product = new ArrayList<String>() {{add("huaweiMate30Pro");add("xiaomi10x5g");}};private Map<String, String> productMap = new HashMap<String, String>() {{put("huaweiMate30Pro", "5999");put("xiaomi10x5g", "4999");}};private List<City> cityList = new ArrayList<City>() {{add(new City("深圳", 1000L));add(new City("杭州", 2000L));add(new City("贵阳", 900L));}};public String showProperty() {return "showProperty-无参数";}public String showProperty(String name) {return "showProperty-" + name;}@Data@AllArgsConstructorstatic class City {private String name;private long population;}
}
  1. SpEl支持和不支持操作支持动态注入实例,类似于对象自动注入SPL不支持直接注入配置文件中的配置支持调用静态和实例方法静态方法:@Value("#{T(package.ClassName).ConstFieldName")支持调用静态类或常量支持运算符运算支持操作集合支持查询筛选集合和投影
  2. 注入完整操作如下
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Map;@Data
@Component
public class SpElConfig {/// 不支持直接注入配置文件值/*@Value("#{com.codecoord.el.num}")private Integer num;*//*** 对象注入*/@Value("#{spElConstant}")private SpElConstant spElConstant;/*** 注入ID为spElConstant Bean中的STR常量/变量*/@Value("#{spElConstant.name}")private String name;/*** 调用无参方法*/@Value("#{spElConstant.showProperty()}")private String method1;/*** 有参接收字符串的方法*/@Value("#{spElConstant.showProperty('Hell SpringEL')}")private String method2;/*** 方法返回的String为大写*/@Value("#{spElConstant.showProperty().toUpperCase()}")private String method3;/*** 若使用method3这种方式,若果showProperty返回为null* 将会抛出NullPointerException,可以使用以下方式避免* 使用?.符号代表若然左边的值为null,将不执行右边方法*/@Value("#{spElConstant.showProperty()?.toUpperCase()}")private String method4;/*** 注入math常量*/@Value("#{T(java.lang.Math).PI}")private double pi;/*** 用random方法获取返回值*/@Value("#{T(java.lang.Math).random()}")private double random;/*** 获取文件路径符号*/@Value("#{T(java.io.File).separator}")private String separator;/*** 拼接字符串*/@Value("#{spElConstant.nickname + ' ' + spElConstant.name}")private String concatString;/*** 对数字类型进行运算,spElConstant拥有num属性*/@Value("#{3 * T(java.lang.Math).PI + spElConstant.num}")private double operation;/*** 进行逻辑运算*/@Value("#{spElConstant.num > 100 and spElConstant.num <= 200}")private boolean logicOperation;/*** 进行或非逻辑操作*/@Value("#{not (spElConstant.num == 100) or spElConstant.num <= 200}")private boolean logicOperation2;/*** 使用三元运算符*/@Value("#{spElConstant.num > 100 ? spElConstant.num : spElConstant.num + 100}")private Integer logicOperation3;/*** 获取下标为0的元素*/@Value("#{spElConstant.product[0]}")private String str;/*** 获取下标为0元素的大写形式*/@Value("#{spElConstant.product[0]?.toUpperCase()}")private String upperStr;/*** 获取map中key为hello的value*/@Value("#{spElConstant.productMap['hello']}")private String mapValue;/*** 根据product下标为0元素作为key获取testMap的value*/@Value("#{spElConstant.productMap[spElConstant.product[0]]}")private String mapStrByproduct;/*** 注入人口大于等于1000人口的城市*/@Value("#{spElConstant.cityList.?[population >= 1000]}")private List<SpElConstant.City> cityList;/*** 注入人口等于900人口的城市*/@Value("#{spElConstant.cityList.?[population == 900]}")private SpElConstant.City city;/*** 注入人口大于等于1000人口的城市,且只保留城市名称*/@Value("#{spElConstant.cityList.?[population >= 1000].![name]}")private List<String> cityName;
}
  1. 注入结果
{"spElConstant": {"name": "SpElConstant-name","nickname": "tianxin","num": 100,"product": ["huaweiMate30Pro","xiaomi10x5g"],"productMap": {"xiaomi10x5g": "4999","huaweiMate30Pro": "5999"},"cityList": [{"name": "深圳","population": 1000},{"name": "杭州","population": 2000},{"name": "贵阳","population": 900}]},"name": "SpElConstant-name","method1": "showProperty-无参数","method2": "showProperty-Hell SpringEL","method3": "SHOWPROPERTY-无参数","method4": "SHOWPROPERTY-无参数","pi": 3.141592653589793,"random": 0.19997238292235787,"separator": "\\","concatString": "tianxin SpElConstant-name","operation": 109.42477796076938,"logicOperation": false,"logicOperation2": true,"logicOperation3": 200,"str": "huaweiMate30Pro","upperStr": "HUAWEIMATE30PRO","mapValue": null,"mapStrByproduct": "5999","cityList": [{"name": "深圳","population": 1000},{"name": "杭州","population": 2000}],"city": {"name": "贵阳","population": 900},"cityName": ["深圳","杭州"]
}
  1. Spring操作外部Properties文件
<!-- 首先通过applicaContext.xml中<util:properties>增加properties文件 -->
<!-- 注意需要引入Spring的util schemea命名空间和注意id属性,id属性将在SpringEL中使用 -->
<util:properties id="db" location="classpath:application.properties"/>
复制代码
public class TestSpringEL {// 注意db为xml文件中声明的id@Value("#{db['jdbc.url']}")private String propertiesValue;
}
  1. SpringEL在使用时仅仅是一个字符串,不易于排错与测试,也没有IDE检查我们的语法,当出现错误时较难检测,复杂的表达式不建议通过SpringEL方式注入。在非必要情况下,不推荐使用SpEl的复杂注入,清晰可读的代码更为重要且有利于排查问题

四、属性自动注入

  1. 上述都是通过指定字段进行注入,可以通过@ConfigurationProperties指定前缀进行自动注入org.springframework.boot.context.properties.ConfigurationProperties
  2. 配置类
user:id: ${random.uuid}name: autowireaddress: unknownwebsite: www.codecoord.comage: ${random.int}
  1. 自动属性注入类通过prefix指定前端为user,然后将会把user.后的类型按照名称进行注入注意必须要提供setter方法
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix = "user")
@Data
public class UserConfig {private String id;private String name;private String address;private String website;private Integer age;
}
  1. 可以通过@EnableConfigurationProperties(value = UserConfig.class)将UserConfig再次强制注入,问题出现在如果UserConfig为第三方jar包内的配置类,则可能出现属性没有注入情况,所以可以指定注入

SpringBoot技术实践-SpELEL表达式相关推荐

  1. Alibaba Code代码索引技术实践:为Code Review提供本地IDE的阅读体验

    作者:曲径     阿里研发基础设施团队 Code Review在研发流程中非常重要,但Web界面中Code Intelligence能力的缺失改变了原有的代码阅读习惯,又增加了阅读成本.本文将介绍阿 ...

  2. 淘宝长辈模式技术实践万字总结

    长辈模式就是:字大.简单. 四个字背后代表是近100人的项目组的努力,更是淘宝人的情怀与坚持.今天我们在帮助老年人更好得使用互联网产品,就是在帮助未来的自己. 背景与机遇 最新一次人口普查,我国60岁 ...

  3. 【工业智能】人工智能之于工业,应当是融入者而非颠覆者;记一场工业场景下的AI技术实践

    2018年1月13日,由极客邦科技InfoQ中国主办的AICon全球人工智能与机器学习技术大会在北京国际会议中心召开.此次大会以"助力人工智能落地"为主题,汇聚了国内外知名企业和顶 ...

  4. 华为开发者大会HDC.Cloud技术探秘:云搜索服务技术实践

    搜索是一个古老的技术,从互联网发展的第一天开始,搜索技术就绽放出了惊人的社会和经济价值.随着信息社会快速发展,数据呈爆炸式增长,搜索技术通过数据收集与处理,满足信息共享与快速检索的需求.基于搜索技术, ...

  5. 使用容器的正确方式,Docker在雪球的技术实践

    " 雪球目前拥有一千多个容器,项目数量大概有一百多个,规模并不是很大.但是得益于容器技术,雪球部署的效率非常高,雪球的开发人员只有几十个,但是每个月的发布次数高达两千多次. 2018 年 5 ...

  6. 计算机书籍-语音识别技术实践

    深度学习:语音识别技术实践 作者:柳若边 出版社:清华大学出版社 出版时间:2019年04月去天猫看看智能鼠标

  7. 下一代超大规模软件定义网络技术实践

    2019独角兽企业重金招聘Python工程师标准>>> 云计算的 IT 架构已经在企业应用中表现出明显优势,但网络设计理念却必须是一种推倒重来的思想.为了适应云计算的灵活.弹性扩展. ...

  8. 实时音视频聊天中超低延迟架构的思考与技术实践

    1.前言 从直播在线上抓娃娃,不断变化的是玩法的创新,始终不变的是对超低延迟的苛求.实时架构是超低延迟的基石,如何在信源编码.信道编码和实时传输整个链条来构建实时架构?在实时架构的基础之上,如果通过优 ...

  9. 阿里移动|《蚂蚁金服移动端高可用技术实践》

    摘要:对于移动技术而言,2017年是继往开来之年.一方面是移动技术领域进入深水区,另一方面移动技术边界和内涵被不断重塑.阿里巴巴希望进一步推动移动应用研发事实标准落地,从而赋能整个行业开发者.在201 ...

最新文章

  1. 车 局部路径规划与避障
  2. docker使用_使用Docker正确的姿势
  3. linux安装 java jdk
  4. Python网络协议模块学习之smtplib
  5. spring-cloud eureka注册发现
  6. React开发(269):事件的绑定-addEventListener
  7. 使用与不使用@RequestBody注解的区别
  8. C# async/await 使用总结
  9. 水水推荐学习PHP必备的函数集[zt]
  10. .NET简谈观察者模式
  11. python中print输出格式_Python print格式化输出
  12. Anylogic学习--------------智能体(可用于复杂装备系统建模)
  13. 三菱服务器显示003C,FX3U/FX3G系列PLC内置定位功能的当前值寄存器是什么?
  14. 怎么把pdf转换成excel
  15. 华为云Centos7搭建hadoop集群二:yum源替换,ssh免密处理,hadoop用户sudo
  16. 6.1_[Java 数组]-数组与二重循环和鸡兔同笼及冒泡排序
  17. C语言杨辉三角和“日本某地谋杀案”习题讲解
  18. JS 音效触发器 / 给动画添加音效
  19. EST | 北大朱怀球组揭示大气微生物与人为活动的关联及对人体健康的影响
  20. 如何 退出ThunderPlatform.exe进程

热门文章

  1. 单片机c语言模块化实例程序设计,单片机C语言模块化编程方法
  2. 企业怎样规划品牌架构做好品牌建设?
  3. matlab解方程实例
  4. 运用大数据深度“捕鼠”
  5. 毒龙、闪龙、速龙、炫龙、皓龙、羿龙各代表什么意思
  6. 企业邮箱购买指南:分享如何购买适合企业的企业邮箱
  7. 实验室安全 | 生物学实验室最毒的16种试剂
  8. vue中关于计算属性
  9. 使用PostMessage解决跨窗体消息传递
  10. dell进入u盘启动模式_图文详解戴尔笔记本怎么设置u盘启动