目录
- 1 背景
- 2 流程:
- 3 举例
- 3.1 自定义的注解
- 3.2 创建的类
- 3.3 创建的扩展类
1 背景
当我们想要在执行完成一个方法的时候,想要将这个方法相关的日志保存到数据库里面,比如这个方法的入参,这个方法的返回的主键的值,那么这个需要使用到spring里面的aop了。也就是功能的扩展,对一个方法功能的扩展。
2 流程:
自定义一个注解,将这个注解放到方法上面,之后利用aop重写一个类,实现功能的扩展,在这个功能的扩展类里面,从注解里面获取到对应的值,注解是放在方法上,这个注解要获取方法参数里面的值,所以要用于SpEL表达式解析.
在扩展类里面,要从注解里面获取到对应的值,之后将值保存到想要保存的数据库里面。
3 举例
3.1 自定义的注解
代码语言:javascript复制``
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface Operator {
public String student() default "";
public String school() default "";
}
3.2 创建的类
代码语言:javascript复制@RestController
@RequestMapping("/my")
public class textmy {
@RequestMapping("/text")
@Operator(student="#student",school = "school")
public String index(String student,String school){
// System.out.println(student);
return student;
}
}
3.3 创建的扩展类
代码语言:javascript复制@Aspect
@Component
public class MyAspect {
/**
* 用于SpEL表达式解析.
*/
private static SpelExpressionParser parser = new SpelExpressionParser();
/**
* 用于获取方法参数定义名字.
*/
private static DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
@Pointcut(" (execution(* com.controller.*.*(..)))")
public void excudeService() {
}
// returning 属性,值代表返回的具体信息,都保存在这个里面
@AfterReturning(returning="rvt",pointcut = "excudeService()")
public void doAfter(JoinPoint joinPoint,Object rvt) {
// 参数 joinPoint 里面存放的是当前接口的 具体 信息
// rvt 代表这个接口返回的数据
// 方法的具体信息
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
// 获取到要扩展的原来的方法
Method method = methodSignature.getMethod();
System.out.println("方法:" method.getName());
try {
// getAnnotation()方法示例【通过反射获取到方法对象再获取方法对象上的注解信息】
这个是获取到一个方法上面 Operator 注解里面的全部的信息
Operator oper = method.getAnnotation(Operator.class);
if (oper != null) {
// 获取到方法上面注解里面的属性的值
String student = oper.student();
String school = oper.school();
//将方法参数设置到上下文中
// 也就是返回了 对应关系
EvaluationContext context = getContext(joinPoint);
// 根据对应关系 和 获取到的注解的形参 ,得到对应的方法参数的值
String s = generateKeyBySpEL(student, context);
String s1 = generateKeyBySpEL(school, context);
// System.out.println("已经进入切面");
System.out.println("这个是获取到的注解里面的值:" s s1);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("记录办理过程出现异常");
}
}
// JoinPoint是原来方法的全部的信息
private EvaluationContext getContext(JoinPoint joinPoint) {
// 通过joinPoint获取被注解方法
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
// 以下是获取到方法所有的信息,都在method里面了
Method method = methodSignature.getMethod();
// 使用spring的DefaultParameterNameDiscoverer获取方法形参名数组
// 也就是将原来方法 里面的形参获得, 也就是形参现在变为数组
String[] paramNames = nameDiscoverer.getParameterNames(method);
// 创建 spring的表达式上下文对象
EvaluationContext context = new StandardEvaluationContext();
//获取传入目标方法的参数 也就是传入的值的集合
Object[] args = joinPoint.getArgs();
// 给上下文赋值,个数通过注解里面的形参进行定
for (int i = 0; i < args.length; i ) {
// 将方法形参 和 注解形参的 对应关系 放到上下文对象里面
context.setVariable(paramNames[i], args[i]);
}
//将上下文对象 ,也就是对应关系 返回
return context;
}
// 上下文处理器,意思是context里面已经有 注解参数和方法参数的对应关系
private String generateKeyBySpEL(String spELString, EvaluationContext context) {
if(StringUtils.isEmpty(spELString)){
return "";
}
// 解析过后的Spring表达式对象
// 获取到spel的对象,也就是一个表达式的对象
Expression expression = parser.parseExpression(spELString);
// 根据对象,从上下文对象里面获取值
return expression.getValue(context).toString();
}
}