zoukankan      html  css  js  c++  java
  • 第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 type)
    • T getProperty(String key, Class 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'}"/>
    
  • 相关阅读:
    BZOJ 1718: [Usaco2006 Jan] Redundant Paths 分离的路径( tarjan )
    BZOJ 1040: [ZJOI2008]骑士( 树形dp )
    BZOJ 1691: [Usaco2007 Dec]挑剔的美食家( 平衡树 )
    HDU 5667 Sequence 矩阵快速幂
    FZU 2225 小茗的魔法阵 扫描线+树状数组
    UVA 11916 Emoogle Grid 离散对数 大步小步算法
    UVA 11754 Code Feat 中国剩余定理+暴力
    FZU 2092 收集水晶 dp+bfs
    FZU2090 旅行社的烦恼 巧妙floyd 最短路
    UVA 11426 GCD
  • 原文地址:https://www.cnblogs.com/charlypage/p/9277390.html
Copyright © 2011-2022 走看看