第3章—高级装配—运行时注入
运行时注入
当我们经常用如下的硬解码方式来配置文件:
<bean id="SgtPeppers" class="com.CDDemo.SgtPeppers" p:title="sgt" p:song="Twinkle, twinkle, little start"> <property name="title" value="sgt"/> <property name="song" value="Twinkle, twinkle, little start"/> </bean>
但有时我们需要避免硬解码,需要想要这些值在运行时确定,Spring提供了两种在运行时求值的方式:
- 属性占位符
- Spring表达式语言(SpEL)
1.注入外部的值
在Spring中,处理外部值得最简单方式就是申明属性源并通过Spring的Enviroment来检索属性.例如:
@Configuration @PropertySource("classpath:app.properties") public class ExpressionTest { @Autowired Environment environment; @Test public BlankDisc disc(){ return new BlankDisc( environment.getProperty("disc.title"), environment.getProperty("disc.artist") ); } }
app.properties
disc.title="titeTest" disc.artist="Twinkle, twinkle, little start"
2.深入学习Spring的Environment
Environment的getProperty()方法有四个重载的变种形式:
- String getProperty(String key)
- String getProperty(String key,String defaultValue)
- T getProperty(String key, Class<T> type)
- T getProperty(String key, Class<T> type,T defaultValue)
前两种形式的getProperty()方法都是返回String类型的值。后两种重载方法不是直接返回字符串,而是将获取到的值转化为指定类型的值,比如获取连接池中维持连接的总数量:
String disc = env.getProperty("disc.title","dukh");
除了属性相关的功能外,Environment还提供了一些方法来检查哪些profile处于激活状态:
- String [] getActiveProfiles():返回激活profile名称的数组;
- String [] getDefaultProfile():返回默认profile名称的数组;
- boolean acceptsPrifiles(String ... profiles):如果environment支持给定的profile返回true。
3.解析属性占位符
Spring一直支持将属性定义到外部的属性文件中,并使用占位符值将其插入到Spring bean中.在Spring装配中,占位符的形式为使用"${...}"包装的属性名称.
比如我们常见的使用数据库连接池的方式:
<!-- 读取db.properties文件. 读取到数据库信息 --> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean>
这里需要注意的是使用Spring context命名空间的<context:property-placeholder location="classpath:db.properties"/>元素将为你生成ProoertySourcesPlacehodlerConfigurer bean.
4.SpEL样例
SpEL的表达式是"#{...}"之中放入相应的计算或者方法调用等,如下所示:
@Value("#{T(System).currentTimeMillis()}") Long time
{T(System).currentTimeMillis()}最终计算的是当前时间的毫秒值.T()表达式会将java.lang.System视为java中对应的类型,因此可以调用其Static修饰的currentTimeMillis()方法.
表示字面值
浮点:
{3.14159}
科学计数法:98700
{9.87E4}
String:
{"Heloo"}
Boolean:
{false}
引用bean,属性和方法
将bean的ID作为SpEL表达式:
{SgtPeppers}
{SgtPeppers.title}
{SgtPeppers.play()}
还可以防止是null的情况 要先进行判断:
{SgtPeppers.play()?.toUpperCase()}
T()运算符的结果是一Class对象,它的真正价值在于它能够访问目标类型的静态方法和常量:
T(java.lang.Math).random()
5.SpEL运算符
SpEL提供了几种运算符,这些运算符可以用在SpEL表达式中的值上。
运算符类型 | 运算符 |
---|---|
算术运算 | +、-、*、/、%、^ |
关系运算 | <、>、==、<=、>=、lt、gt、eq、le、ge |
逻辑运算 | and、or、not、| |
条件运算 | ?:(ternary)、?:(Elvis) |
正则表达式 | matches |
数值运算
<!-- +运算符:两个数字相加 --> <property name="adjustedAmount" value="#{counter.total + 42}"/> <!-- +运算符:用于连接字符串 --> <property name="fullName" value="#{performer.firstName + ' ' + performer.lastName}"/> <!-- -运算符:两个数字相减 --> <property name="adjustedAmount" value="#{counter.total - 20}"/> <!-- *运算符:乘法运算 --> <property name="circumference" value="#{2 * T(java.lang.Math).PI * circle.radius}"/> <!-- /运算符:除法运算 --> <property name="average" value="#{counter.total / counter.count}"/> <!-- %运算符:求余运算 --> <property name="remainder" value="#{counter.total % counter.count}"/> <!-- ^运算符:乘方运算 --> <property name="area" value="#{T(java.lang.Math).PI * circle.radius ^ 2}"/>
比较值
比较两个值是否相等,可以使用”==”运算符:
<!-- 假设equal属性为布尔属性 --> <property name="equal" value="#{counter.total == 100}"/>
逻辑表达式
运算符 | 操作 |
---|---|
and | 逻辑AND运算操作,只有运算符两边都是true,表达式才能是true |
or | 逻辑OR运算操作,只要运算符的任意一边是true,表达式就会是true |
not或! | 逻辑NOT运算操作,对运算结果求反 |
<!-- and 运算符 --> <property name="largeCircle" value="#{shape.kind == 'circle' and shape.perimeter gt 10000}"/> <!-- ! 运算符 --> <property name="outOfStock" value="#{!product.availiable}"/> <!-- not 运算符 --> <property name="outOfStock" value="#{not product.availiable}"/>
条件表达式
<!-- ?:三元运算符 --> <property name="song" value="#{kenny.song != null ? kenny.song : 'Greensleeves'}"/>
正则表达式
<!-- 判断一个字符串是否是有效的邮件地址 --> <property name="validEmail" value="#{admin.email matches '[a-zA-Z0-9.-%+-]+@[a-zA-Z0-9.-]+\\.com'}"/>

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Spring Boot入门(11)实现文件下载功能
在这篇博客中,我们将展示如何在Spring Boot中实现文件的下载功能。 还是遵循笔者写博客的一贯风格,简单又不失详细,实用又能让你学会。 本次建立的Spring Boot项目的主要功能为文件下载,而且这也是唯一功能,当然,作为例子,要尽可能简单,所以,功能简化为只下载E盘music_eg目录下的某一个文件。 该Spring Boot项目的名称为file_download,其具体结构如下: build.gradle文件的代码如下: buildscript { ext { springBootVersion = '2.0.3.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework...
- 下一篇
Java复习2-对象与类
回顾基础知识过程中遇到的感觉需要记录一下的知识点。 封装 我们设计的class应当尽可能的高内聚,体现为封装的程度。一个class的属性应该只能自己修改,其他class都只是与本class沟通,而不应该有能力修改。比较常见的一个问题是Date属性。 业务开发中经常需要设计class的日期属性,比如birthday, createDate等。 public class User { private String name; private Date birth; public Date getBirth() { return this.birth; } } 我经常设计一个entity,填入字段,然后就直接getter, setter出去,尤其使用lombok后,更是连生成都改自动了。按照封装的要求,这样的做法是不合适的。因为其他class可以获取Date对象,Date对象是可变的。那么,就有可能会产生日期被修改的可能。 如果项目有引入Findbugs的扫描,这个class肯定会被扫描出来的,不应该返回一个可变对象。那么,怎么做才可以避免这个问题?我们确实需要暴露Date啊。 答案是暴露一...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS6,CentOS7官方镜像安装Oracle11G
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS8编译安装MySQL8.0.19