文章目录
一、概要
1.首先–简要的介绍本文所要记录的内容
- 使用spring的AOP加注解实现对公有技术代码抽取以便灵活使用及代码简化
- 使用断言结合统一异常处理–我的上一文对常见验证判断进行处理,简化代码层次(对少写if嵌套大有裨益),从而优化代码层级结构
2.其次–优点及好处
- 公有技术代码抽取
- 秉承约定大于配置的思想,使用spring的AOP加注解对公有技术代码抽取可以做到使用更便利及灵活
- 我们首先要定义一个职能注解,然后编写好此注解所代表的aop功能逻辑,当我们想要对一个方法进行此功能增强时只要在此方法上定义此职能注解,就能对此方法进行增强
- 对方法进行功能增强,spring的AOP本身就是做这个事的,结合注解的好处/区别在于,对于切点的定义以及功能的显式呈现
- 如果AOP使用切点表达式而不结合注解,就要着重设计切点表达式的书写,其次一次定型,如 “execution(* com.lil.aop..(…))”
表示任意返回值、aop包下任意类的任意参数的任意方法(此类写法最为常用),此时就是aop包下所有方法进行增强,如果需求是增强其中一个的几个方法,用这种方法就可能要掉头发了 - 如果结合注解只需在要被增强的方法上定义注解即会被增强,对于改需求优势就更打了,需要增强就加注解,不需要删除注解即可
- 断言结合统一异常处理
- 在WEB开发中对入参、返回值及数据库查询结果的数据验证必不可免,断言可对数据进行验证,不符合即时抛出异常
- 断言处抛出的异常如果结合全局异常处理就可以使得代码结构更加简洁,层级更加清晰,可以让大家伙抄起代码来也更加得心应手
第一步、定义注解
- 作用范围为runtime
- 作用类型为方法
- 属性根据需求,要才定义
第二步、书写工具类
- 工具方法没几行,在此就不赘述了,作用就是解析el表达式
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;
/**
* -*-codeing=utf-8-*-
*
* @version : 1.0
* @time : 2022/4/5 20:25
* @Author : 黑马户-BCD
* @File : xin.ucode.front.aspect.SpelParser
* @Software : IntelliJ IDEA
*/
public class SpelParser {
private static ExpressionParser parser = new SpelExpressionParser();
public static String getKey(String key, String[] parameterNames, Object[] args){
//第一步: 将key字符串解析为el表达式
Expression exp = parser.parseExpression(key);
//第二步: 将形参和形参值以配对的方式配置到赋值上下文中
EvaluationContext context = new StandardEvaluationContext();
if (args.length<=0){
return null;
}
for (int i = 0; i < args.length; i++) {
context.setVariable(parameterNames[i],args[i]);
}
//第三步: 根据复制上下文运算el表达式
return exp.getValue(context, String.class);
}
}
第三步、书写切面增强逻辑
- 注释我写的很清晰,望着字过目
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.springframework.stereotype.Component;
import xin.ucode.front.annotation.DoSomething;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* -*-codeing=utf-8-*-
*
* @version : 1.0
* @time : 2022/4/5 18:50
* @Author : 黑马户-BCD
* @File : xin.ucode.front.aspect.DoSomethingAspect
* @Software : IntelliJ IDEA
*/
@Aspect//定义切面
@Component//依赖注入
public class DoSomethingAspect {
//因为入参定义了dst变量的类型为DoSomething ,所以所有加了DoSomething注解的方法都会被增强
@Around("@annotation(dst)")
public Object doAround(ProceedingJoinPoint pjp, DoSomething dst) throws Throwable {
//前置增强打印
System.out.println("hei---------------------------hei");
//此处使用上面已写的工具方法对入参根据el表达式进行解析
String key = getKey(dst.key(),pjp);//此方法中对未解析的el表达式进行了打印
//打印解析后的入参值--测试结果处可看到打印了实际值
System.out.println("key = " + key);
//方法执行
Object proceed = pjp.proceed();
//后置增强打印
System.out.println("hhh---------------------------hhh");
//返回方法执行所得返回值
return proceed;
}
private String getKey(String key, ProceedingJoinPoint pjp){
//打印el表达式
System.out.println("key-----------------= " + key);
//反射获取方法对象
Method method = ((MethodSignature) (pjp.getSignature())).getMethod();
//反射获取方法参数数组
Parameter[] parameters = method.getParameters();
String[] parameterNames = new String[parameters.length];
for (int i = 0; i < parameters.length; i++) {
//获取到所有参数名
parameterNames[i]=parameters[i].getName();
}
//使用工具类获得el表达式替代的参数值
return SpelParser.getKey(key,parameterNames,pjp.getArgs());
}
}
第四步、使用注解对方法进行功能增强
第五步、测试
第六步、结果截图
- 首先在方法执行前进行了增强打印
- 其次打印了注解中配置的el表达式
- 然后打印了方法入参的实际值
- 最后在方法执行后进行了增强打印
第七步、总结
- 至此,我们可以做到对指定方法进行增强只要在其上标注注解即可
演示之中我只是获取了方法入参做了打印测试,各位在日后的使用当中可以随意结合自己的功能逻辑随意增强,入参返回值等数据更可结合断言简洁代码,美哉!美哉!- 对于读写缓存,写入日志等公有技术代码进行抽取可谓功在千秋的做法
- 我觉得很多框架注解增强的实现思路与此应该大差不差
末尾、浅示断言
-
实现断言验证数据库查询结果只能查到一个结果,不是一个结果即抛异常
-
根据业务自定义断言抛出异常规则
-
自定义断言继承自org.springframework.util.Assert即可对spring断言根据业务需求进行增强
-
org.springframework.util.Assert中的非空断言逻辑
- 断言就不多言了,实际之中用多了就会觉得还是很nice的