第3章—高级装配—运行时注入

简介: 运行时注入当我们经常用如下的硬解码方式来配置文件: 但有时我们需要避免硬解码,需要想要这些值在运行时确定,Spring提供了两种在运行时求值的方式:属性占位符Spring表达式语言(SpEL)1.

运行时注入

当我们经常用如下的硬解码方式来配置文件:
AI 代码解读
<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>
AI 代码解读

但有时我们需要避免硬解码,需要想要这些值在运行时确定,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")
        );
    }
}

AI 代码解读

app.properties

disc.title="titeTest"
disc.artist="Twinkle, twinkle, little start"
AI 代码解读

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");
AI 代码解读

除了属性相关的功能外,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>
AI 代码解读

​ 这里需要注意的是使用Spring context命名空间的<context:property-placeholder location="classpath:db.properties"/>元素将为你生成ProoertySourcesPlacehodlerConfigurer bean.

4.SpEL样例

SpEL的表达式是"#{...}"之中放入相应的计算或者方法调用等,如下所示:

 @Value("#{T(System).currentTimeMillis()}") Long time
AI 代码解读

{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}"/>
AI 代码解读

比较值

比较两个值是否相等,可以使用”==”运算符:

<!-- 假设equal属性为布尔属性 -->
<property name="equal" value="#{counter.total == 100}"/>
AI 代码解读

逻辑表达式

运算符 操作
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}"/>
AI 代码解读

条件表达式

<!-- ?:三元运算符 -->
<property name="song" value="#{kenny.song != null ? kenny.song : 'Greensleeves'}"/>
AI 代码解读

正则表达式

<!-- 判断一个字符串是否是有效的邮件地址 -->
<property name="validEmail" value="#{admin.email matches '[a-zA-Z0-9.-%+-]+@[a-zA-Z0-9.-]+\\.com'}"/>
AI 代码解读
相关文章
spring框架之AOP模块(面向切面),附带通知类型---超详细介绍
spring框架之AOP模块(面向切面),附带通知类型---超详细介绍
128 0
Spring框架入门以及 ioc的三种注入方式
Spring框架入门以及 ioc的三种注入方式
387 0
|
7月前
|
Spring注解开发定义bean及纯注解开发模式
Spring注解开发定义bean及纯注解开发模式
61 0
.net core工具组件系列之Autofac—— 第二篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
本篇文章接前一篇,建议可以先看前篇文章,再看本文,会有更好的效果。前一篇跳转链接:https://www.cnblogs.com/weskynet/p/15046999.html
655 0
.net core工具组件系列之Autofac—— 第二篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
285 24
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
65 1
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
Could not autowire No beans of ‘UserSerice,这样的bug,主要是idea检测到你没有往页面中,没有往容器中注入一个userService,容器注入UserSe
Could not autowire No beans of ‘UserSerice,这样的bug,主要是idea检测到你没有往页面中,没有往容器中注入一个userService,容器注入UserSe
高级对象装配:解析Spring创建复杂对象的秘诀
高级对象装配:解析Spring创建复杂对象的秘诀
62 0
高级对象装配:解析Spring创建复杂对象的秘诀
|
7月前
|
注入工具 -- DSSS
注入工具 -- DSSS
57 0
spring框架入门介绍以及IOC的三种注入方式
spring框架入门介绍以及IOC的三种注入方式
251 0
AI助理

阿里云 AI 助理已上线!

快来体验一下吧。