您好,登錄后才能下訂單哦!
這篇文章主要介紹了怎么用Spring的spel獲取自定義注解參數值的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇怎么用Spring的spel獲取自定義注解參數值文章都會有所收獲,下面我們一起來看看吧。
package com.xxx.mall.order.service.component; import java.lang.annotation.*; /** * 庫存不足等信息監控 * Created by xdc on 2019/4/16 15:43 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented public @interface StockWarnCollect { /** 客戶id */ String customerId(); /** 來源 */ String source(); /** 請求類型 1:詳情頁 2:購物車去結算 3:提交訂單 */ String pageType(); }
@Override @StockWarnCollect(customerId = "#customerId", source = "#source", pageType = "2") public Map<String, Object> validateCarts(Long customerId, Set<Long> userSelectedIds, Short source, JSONArray couponInfo){ // 省略 }
import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 下單失敗、庫存監控 * Created by xdc on 2019/4/16 15:45 */ @Aspect @Component @Slf4j public class StockWarnCollectAop { @Pointcut(value = "@annotation(com.xxx.mall.order.service.component.StockWarnCollect)") public void collectStockWarn(){} @Around(value = "collectStockWarn()") public Object around(ProceedingJoinPoint pjp) throws Throwable { Method targetMethod = this.getTargetMethod(pjp); StockWarnCollect stockWarnCollect = targetMethod.getAnnotation(StockWarnCollect.class); // spel信息 String customerIdSpel = stockWarnCollect.customerId(); String sourceSpel = stockWarnCollect.source(); Integer pageType = null; // 操作類型,純字符串 if (StringUtils.isNotBlank(stockWarnCollect.pageType())) { pageType = Integer.valueOf(stockWarnCollect.pageType()); } // 客戶id、來源解析 ExpressionParser parser = new SpelExpressionParser(); LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); String[] params = discoverer.getParameterNames(targetMethod); Object[] args = pjp.getArgs(); EvaluationContext context = new StandardEvaluationContext(); for (int len = 0; len < params.length; len++) { context.setVariable(params[len], args[len]); } Expression expression = parser.parseExpression(customerIdSpel); Long customerId = expression.getValue(context, Long.class); expression = parser.parseExpression(sourceSpel); Short source = expression.getValue(context, Short.class); log.info("collectStockWarn customerId:{}, source:{}", customerId, source); // 業務邏輯處理 Object result = null; try { result = pjp.proceed(); } catch (Throwable e) { log.info("collectStockWarn watchs creating order errorMsg:{}", ExceptionUtils.getStackTrace(e)); if (e instanceof MallException) { } else { // 未知錯誤 } throw e; } try { if (result != null) { } } catch (Exception e) { log.error("collectStockWarn process error, errorMsg:{}", ExceptionUtils.getStackTrace(e)); } return result; } /** * 獲取目標方法 */ private Method getTargetMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException { Signature signature = pjp.getSignature(); MethodSignature methodSignature = (MethodSignature)signature; Method agentMethod = methodSignature.getMethod(); return pjp.getTarget().getClass().getMethod(agentMethod.getName(),agentMethod.getParameterTypes()); } }
SpEL(Spring Expression Language),即Spring表達式語言,是比JSP的EL更強大的一種表達式語言。為什么要總結SpEL,因為它可以在運行時查詢和操作數據,尤其是數組列表型數據,因此可以縮減代碼量,優化代碼結構。個人認為很有用。
1.1 SpEL 字面量:
整數:#{8}
小數:#{8.8}
科學計數法:#{1e4}
String:可以使用單引號或者雙引號作為字符串的定界符號。
Boolean:#{true}
1.2 SpEL引用bean , 屬性和方法:
引用其他對象:#{car}
引用其他對象的屬性:#{car.brand}
調用其它方法 , 還可以鏈式操作:#{car.toString()}
調用靜態方法靜態屬性:#{T(java.lang.Math).PI}
1.3 SpEL支持的運算符號:
算術運算符:+,-,*,/,%,^(加號還可以用作字符串連接)
比較運算符:< , > , == , >= , <= , lt , gt , eg , le , ge
邏輯運算符:and , or , not , |
if-else 運算符(類似三目運算符):?:(temary), ?:(Elvis)
正則表達式:#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}'}
SpEL有三種用法:
1. 是在注解@Value中;
2. 在XML配置中;
3. 代碼塊中使用Expression。
2.1 @Value
//@Value能修飾成員變量和方法形參 //#{}內就是表達式的內容 @Value("#{表達式}") public String arg;
2.2 <bean>配置
<bean id="xxx" class="com.java.XXXXX.xx"> <!-- 同@Value,#{}內是表達式的值,可放在property或constructor-arg內 --> <property name="arg" value="#{表達式}"> </bean>
2.3 代碼塊中使用
public class SpELTest { public static void main(String[] args) { //創建ExpressionParser解析表達式 ExpressionParser parser = new SpelExpressionParser(); //表達式放置 Expression exp = parser.parseExpression("表達式"); //執行表達式,默認容器是spring本身的容器:ApplicationContext Object value = exp.getValue(); /**如果使用其他的容器,則用下面的方法*/ //創建一個虛擬的容器EvaluationContext StandardEvaluationContext ctx = new StandardEvaluationContext(); //向容器內添加bean BeanA beanA = new BeanA(); ctx.setVariable("bean_id", beanA); //setRootObject并非必須;一個EvaluationContext只能有一個RootObject,引用它的屬性時,可以不加前綴 ctx.setRootObject(XXX); //getValue有參數ctx,從新的容器中根據SpEL表達式獲取所需的值 Object value = exp.getValue(ctx); } }
#{…} 用于執行SpEl表達式,并將內容賦值給屬性
${…} 主要用于加載外部屬性文件中的值
#{…} 和${…} 可以混合使用,但是必須#{}外面,${}在里面
4.1 ${…}用法
{}里面的內容必須符合SpEL表達式,通過@Value(“${spelDefault.value}”)可以獲取屬性文件中對應的值,但是如果屬性文件中沒有這個屬性,則會報錯。可以通過賦予默認值解決這個問題,如@Value("${spelDefault.value:127.0.0.1}")
// 如果屬性文件沒有spelDefault.value,則會報錯 // @Value("${spelDefault.value}") // private String spelDefault2; // 使用default.value設置值,如果不存在則使用默認值 @Value("${spelDefault.value:127.0.0.1}") private String spelDefault;
4.2 #{…}用法
這里只演示簡單用法
// SpEL:調用字符串Hello World的concat方法 @Value("#{'Hello World'.concat('!')}") private String helloWorld; // SpEL: 調用字符串的getBytes方法,然后調用length屬性 @Value("#{'Hello World'.bytes.length}") private String helloWorldbytes;
4.3 ${…}和#{…}混合使用
${...}和#{...}可以混合使用,如下文代碼執行順序:通過${server.name}從屬性文件中獲取值并進行替換,然后就變成了 執行SpEL表達式{‘server1,server2,server3’.split(‘,’)}。
// SpEL: 傳入一個字符串,根據","切分后插入列表中, #{}和${}配置使用(注意單引號,注意不能反過來${}在外面,#{}在里面) @Value("#{'${server.name}'.split(',')}") private List<String> servers;
在上文中在#{}外面,${}在里面可以執行成功,那么反過來是否可以呢${}在外面,#{}在里面,如代碼
// SpEL: 注意不能反過來${}在外面,#{}在里面,這個會執行失敗 @Value("${#{'HelloWorld'.concat('_')}}") private List<String> servers2;
答案是不能。因為spring執行${}是時機要早于#{}。在本例中,Spring會嘗試從屬性中查找#{‘HelloWorld’.concat(‘_’)},那么肯定找不到,由上文已知如果找不到,然后報錯。所以${}在外面,#{}在里面是非法操作
關于“怎么用Spring的spel獲取自定義注解參數值”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“怎么用Spring的spel獲取自定義注解參數值”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。