Spring spel获取自定义注解参数值方式

网友投稿 1779 2022-10-30

Spring spel获取自定义注解参数值方式

Spring spel获取自定义注解参数值方式

目录spel获取自定义注解参数值1.注解类2.注解使用3.aop中处理 spel在注解中的使用1 语法说明2. 基本用法4 #{…}和${…}

spel获取自定义注解参数值

1.注解类

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();

}

2.注解使用

@Override

@StockWarnCollect(customerId = "#customerId", source = "#source", pageType = "2")

public Map validateCarts(Long customerId, Set userSelectedIds, Short source, jsONArray couponInfo){

// 省略

}

3.aop中处理

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.ahttp://nnotation.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在注解中的使用

SpEL(Spring Expression Language),即Spring表达式语言,是比JSP的EL更强大的一种表达式语言。为什么要总结SpEL,因为它可以在运行时查询和操作数据,尤其是数组列表型数据,因此可以缩减代码量,优化代码结构。个人认为很有用。

1 语法说明

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}'}

2. 基本用法

SpEL有三种用法:

1. 是在注解@Value中;

2. 在XML配置中;

3. 代码块中使用Expression。

2.1 @Value

//@Value能修饰成员变量和方法形参

//#{}内就是表达式的内容

@Value("#{表达式}")

public String arg;

2.2 配置

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 vhttp://alue = exp.getValue(ctx);

}

}

4 #{…}和${…}

#{…} 用于执行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 servers;

在上文中在#{}外面,${}在里面可以执行成功,那么反过来是否可以呢${}在外面,#{}在里面,如代码

// SpEL: 注意不能反过来${}在外面,#{}在里面,这个会执行失败

@Value("${#{'HelloWorld'.concat('_')}}")

private List servers2;

答案是不能。因为spring执行${}是时机要早于#{}。在本例中,Spring会尝试从属性中查找#{‘HelloWorld’.concat(‘_’)},那么肯定找不到,由上文已知如果找不到,然后报错。所以${}在外面,#{}在里面是非法操作

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:绿色篮子小程序开发
下一篇:ASCII字符显示例子
相关文章

 发表评论

暂时没有评论,来抢沙发吧~