AOP不用多说,是spring框架的两大基石之一。SpEL是Spring Expression Language的缩写,意为Spring表达式语言,,其支持在运行时查询和操作对象图提供了更加丰富的功能,最特别的是方法调用与字符串模板功能。熟悉js的es6语法的小伙伴都知道,模板字符串,这个spel就类似js的模板字符串。
本次代码主要是熟悉使用语法,并布对应实际的应场景。
一、自定义注解
java
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAopAnn {
/**
* spEL
* @return
*/
String spEL() default "";
}
二、自定义切面
java
@Aspect
@Component
public class TestAopAspect {
private final static Logger LOGGER = LoggerFactory.getLogger(TestAopAspect.class);
@Pointcut("@annotation(org.example.boot3.aop.TestAopAnn)")
public void pointCut(){}
@AfterReturning(value = "pointCut()",returning = "result")
public void doAfter(JoinPoint joinPoint,Object result){
Method method = getMethod(joinPoint);
TestAopAnn annotation = method.getAnnotation(TestAopAnn.class);
if(annotation!=null){
LOGGER.info("TestAopAspect-->doAfter-------后置织入");
/// 通过spel表达式获取到形参的中name的值
String value =getValue(joinPoint, method, annotation.spEL());
LOGGER.info("TestAopAspect-->doBefore-------value={}",value);
/// 将name追加到返回的list
try {
if(result!=null && result instanceof List){
List list = (List) result;
list.add(value);
}
} catch (Exception e) {
e.fillInStackTrace();
}
}
}
private Method getMethod(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
return methodSignature.getMethod();
}
/**解析spel*/
private String getValue(JoinPoint joinPoint, Method method,String elStr){
StandardEvaluationContext context = new StandardEvaluationContext();
DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
/// 方法参数名称
String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
Assert.isTrue(parameterNames!=null,"参数列表不能为空");
///方法参数值
Object[] args = joinPoint.getArgs();
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i],args[i]);
}
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(elStr);
return (String) expression.getValue(context);
}
}
三、测试接口
java
public class TestReqVO {
private String name;
private String remark;
}
java
@RestController
@RequestMapping("/api")
public class RestApi {
/**
* SpEL 调用对象方法
* @param vo
* @return
*/
@GetMapping("/testSpEL1")
@TestAopAnn(spEL = "#vo.getName()")
public List<String> getSpELList1(TestReqVO vo){
String[] arr = { "C" ,"C++","JAVA","GoLang","Rust","Python"};
return new ArrayList<>(Arrays.stream(arr).toList());
}
/**
* SpEL 调用对象属性
* @param vo
* @return
*/
@GetMapping("/testSpEL2")
@TestAopAnn(spEL = "#vo.name")
public List<String> getSpELList2(TestReqVO vo){
String[] arr = { "C" ,"C++","JAVA","GoLang","Rust","Python"};
return new ArrayList<>(Arrays.stream(arr).toList());
}
@GetMapping("/fluxList")
public Flux<List<String>> getSpEL2(){
String[] arr = { "C" ,"C++","JAVA","GoLang","Rust","Python"};
ArrayList<String> list = new ArrayList<>(Arrays.asList(arr));
return Flux.just(list);
}
}