Spring 核心特性之表达式(SpEL)_spring spel-优快云博客 -- 写的还行
https://www.jianshu.com/p/14e54863faae spring bean方法的调用
关于SpEL的几个概念:
- 表达式(“干什么”):SpEL的核心,所以表达式语言都是围绕表达式进行的。
- 解析器(“谁来干”):用于将字符串表达式解析为表达式对象。
- 上下文(“在哪干”):表达式对象执行的环境,该环境可能定义变量、定义自定义函数、提供类型转换等等。
- root根对象及活动上下文对象(“对谁干”):root根对象是默认的活动上下文对象,活动上下文对象表示了当前表达式操作的对象。
//获得一个SpEL解析器PARSER
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
//获得一个SpEL解析模板PARSER_TEMPLATE
private static final TemplateParserContext PARSER_TEMPLATE = new TemplateParserContext();
//获得一个Expression表达式对象
Expression exp = PARSER.parseExpression(spEL, PARSER_TEMPLATE);
可以使用 #variableName
的形式引用变量,变量在 EvaluationContext#setVariable
上进行设置,变量名只能包含字母 A
到Z
,a
到z
、数字 0
到 9
、下划线 _
以及美元符号 $
。变量使用示例如下。
//调用对象属性值 public static void main(String[] args) { // Create and set a calendar GregorianCalendar c = new GregorianCalendar(); c.set(1856, 7, 9); //构造一个对象, The constructor arguments are name, birthday, and nationality. Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian"); ExpressionParser parser = new SpelExpressionParser(); //对应方法: Object getValue(@Nullable Object rootObject) Expression exp = parser.parseExpression("name"); // Parse name as an expression String name = (String) exp.getValue(tesla); System.out.println(name); // name == "Nikola Tesla" exp = parser.parseExpression("name == 'Nikola Tesla'"); boolean result = exp.getValue(tesla, Boolean.class); System.out.println(result); // result == true }
//设置全局参数, 参数取值 public static void main(String[] args) { ExpressionParser parser = new SpelExpressionParser(); //#end 变量取值 Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)"); EvaluationContext context = new StandardEvaluationContext(); context.setVariable("end", "!"); System.out.println(expression.getValue(context)); }
#被调用方法 @Data @NoArgsConstructor @AllArgsConstructor public class CustomFunctions { private String name; public static boolean isMember(String name) { // 在这里编写检查是否为会员的逻辑,这里只是一个示例 if (name.equals("Mihajlo Pupin")) { return true; } else { return false; } } }//spel表达式中, 调用非静态方法 public static void main(String[] args) { // 方式1: // StandardEvaluationContext context = new StandardEvaluationContext(); // context.registerFunction("isMember", CustomFunctions.class.getDeclaredMethod("isMember", String.class)); //注册自定义函数 // 方式2: EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); context.setVariable("isMember", CustomFunctions.class.getDeclaredMethod("isMember", String.class));//通过变量方式执行方法 SpelExpressionParser parser = new SpelExpressionParser(); boolean isMember = parser.parseExpression("#isMember('Mihajlo Pupin1')").getValue(context, Boolean.class); System.out.println(isMember); }/** * 调用Bean 中的方法 * 如果解析上下文已经配置,那么bean解析器能够 从表达式使用(@)符号查找bean类。 * */ public static void main(String[] args) { // 1.创建表达式解析器 ExpressionParser parser = new SpelExpressionParser(); // 2.创建变量上下文,设置变量 StandardEvaluationContext context = new StandardEvaluationContext(); // 此处用DefaultListableBeanFactory做测试,系统运行时可传入ApplicationContext DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerSingleton("user", new CustomFunctions("成龙")); context.setBeanResolver(new BeanFactoryResolver(beanFactory)); // 3. spel解析器执行表达式取得结果 System.out.println(parser.parseExpression("@user.getName()").getValue(context, String.class)); CustomFunctions customFunctions = parser.parseExpression("@user").getValue(context, CustomFunctions.class); System.out.println(customFunctions); System.out.println(customFunctions == beanFactory.getBean("user")); }
package com.example.demo.aop; import com.example.demo.annotation.DistributedLock; import java.lang.reflect.Method; import java.rmi.ServerException; import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.expression.Expression; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Component; /** * @Description: * @Author: lwh * @Date: 2023/12/08 * @Version: V1.0 * @Desc: AOP实现分布式锁(spel 支持bean调用) */ @Slf4j @Aspect @Component public class RedisDistributedLockAspect implements BeanFactoryAware { @Autowired RedissonClient redissonClient; //定义解析的模板 例如org.springframework.expression.common.TemplateParserContext类,默认是以#{开头,以#结尾 private static final TemplateParserContext TEMPLATE_PARSER_CONTEXT = new TemplateParserContext(); //定义解析器 private static final SpelExpressionParser SPEL_EXPRESSION_PARSER = new SpelExpressionParser(); //定义评估的上下文对象 默认实现是org.springframework.expression.spel.support包中的StandardEvaluationContext类, // 使用setRootObject方法来设置根对象; // 使用setVariable方法来注册自定义变量; // 使用registerFunction来注册自定义函数等等; private final StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext(); //获取到Spring容器的beanFactory对象 private BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; //填充evaluationContext对象的`BeanFactoryResolver`。 this.standardEvaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory)); } @Around("@annotation(distributedLock)") public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable { long leaseTime = distributedLock.leaseTime(); long waitTime = distributedLock.waitTime(); String errorDesc = distributedLock.errorDesc(); String lockKey = this.getRedisKey(joinPoint, distributedLock); lockKey = lockKey.startsWith("zpqa:") ? lockKey : StringUtils.join("zpqa:", lockKey); Object var8; RLock rLock = redissonClient.getLock(lockKey); try { boolean lock = rLock.tryLock(leaseTime, waitTime, TimeUnit.SECONDS); log.info("DistributedLockHandler#lockName={} result={}", lockKey, lock); if (!lock) { throw new ServerException(errorDesc); } var8 = joinPoint.proceed(); } catch (Throwable throwable) { log.warn("DistributedLockHandler#lock error。。。。", throwable); throw throwable; } finally { if (rLock.isLocked() && rLock.isHeldByCurrentThread()) { rLock.unlock(); } } return var8; } /** * 获取加锁的key * * @param joinPoint * @param distributedLock * @return */ private String getRedisKey(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable { String key = distributedLock.key(); Object[] parameterValues = joinPoint.getArgs(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); //获取方法的注解 Object proceed = joinPoint.proceed(); DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer(); String[] parameterNames = nameDiscoverer.getParameterNames(method); //未指定key, 以入参作为key if (StringUtils.isEmpty(key)) { if (parameterNames != null && parameterNames.length > 0) { StringBuffer sb = new StringBuffer(); int i = 0; for (int len = parameterNames.length; i < len; ++i) { sb.append(parameterNames[i]).append(" = ").append(parameterValues[i]); } key = sb.toString(); } else { key = "lock:redisson"; } return key; } else { Expression expression = SPEL_EXPRESSION_PARSER.parseExpression(key); //参数名称不为空 if (parameterNames != null && parameterNames.length != 0) { for (int i = 0; i < parameterNames.length; ++i) { standardEvaluationContext.setVariable(parameterNames[i], parameterValues[i]); } try { Object expressionValue = expression.getValue(standardEvaluationContext); //expression1.getValue(this.standardEvaluationContext, proceed, method.getReturnType()); return expressionValue != null && !"".equals(expressionValue.toString()) ? expressionValue.toString() : key; } catch (Exception exception) { log.warn("DistributedLockHandler#解析参数异常 error={}", exception); throw new RuntimeException("参数解析异常"); } } else { return key; } } /** * 1. resolve(logAnno.typeExpression()得到的值为:#{@ELService.x(#root)}。 * 2. parseExpression解析后得到实际字符串为@ELService.x(#root)表达式。 * 3. getValue去bean容器中执行ELService类的x方法。当然参数是context的#root对象。通过proceed传入。 * 4. 最终返回的类型为method.getReturnType()原方法的类型 */ // return PARSER.parseExpression(resolve(logAnno.typeExpression()), PARSER_CONTEXT) // .getValue(this.evaluationContext, proceed, method.getReturnType()); } /** * 作用是读取yml里面的值 * @param value 例如:1. #{${ttt.xxx}}会读取yml的ttt.xxx: read配置值,替换为#{read} * 2.#{read}直接返回#{read} * @return #{read} */ private String resolve(String value) { if (this.beanFactory != null && this.beanFactory instanceof ConfigurableBeanFactory) { return ((ConfigurableBeanFactory) this.beanFactory).resolveEmbeddedValue(value); } return value; } }