自定义注解2-动态修改注解的属性值
时间:2022-07-28
本文章向大家介绍自定义注解2-动态修改注解的属性值,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
经过上一节的,我们可以自己解析spel表达式。那么我现在的想法是,在注解的第一层aop中解析spel,然后将解析后的值设置到属性中,那么在之后的aop中就不用解析了。
找出注解中值存放位置
继续上一节的代码,在上一节的AOP中添加注解@Order(0),再新增一个注解,添加@Order(1)。注意order这个注解有坑的,最好先百度完再使用。
@Component
@Aspect
@Order(0)
public class InterestResolveELAspect {
// resolve spel...
}
@Component
@Aspect
@Order(1)
public class InterestHandleAspect {
@Around("@annotation(anno)")
public Object invoked(ProceedingJoinPoint pjp, Interest anno) throws Throwable {
String key = anno.key();
String unless = anno.unless();
logger.info("call InterestHandleAspect.invoked, resolvedKey:[{}], resolvedUnless:[{}]"
, key, unless);
return pjp.proceed();
}
}
我们在上一节代码中的String keySpel = anno.key()打下断点。查看当前栈的变量。
发现注解的对象是一个Proxy的实例,Proxy的作用就是为java类生一个代理对象,有这个代理对象去调用真实方法,就像这样
public interface A {
String func1();
}
public class B implements A {
@Override
public String func1() { //do something ... }
public String func2() { //do something ... };
}
public static void main(String ...args) {
B bInstance = new B();
B bProxy = Proxy.newProxyInstance(
B.class.getClassLoader(), // B 类的类加载器
B.class.getInterfaces(), // B 类所实现的接口,如果你想拦截B类的某个方法,必须让这个方法在某个接口中声明并让B类实现该接口
new InvocationHandler() { // 调用处理器,任何对 B类所实现的接口方法的调用都会触发此处理器
@Override
public Object invoke (Object proxy, // 这个是代理的实例,method.invoke时不能使用这个,否则会死循环
Method method, // 触发的接口方法
Object[] args // 此次调用该方法的参数
) throws Throwable {
System.out.println(String.format("调用 %s 之前", method.getName()));
/**
* 这里必须使用B类的某个具体实现类的实例,因为触发时这里的method只是一个接口方法的引用,
* 也就是说它是空的,你需要为它指定具有逻辑的上下文(bInstance)。
*/
Object obj = method.invoke(bInstance, args);
System.out.println(String.format("调用 %s 之后", method.getName()));
return obj; //返回调用结果
}
}
);
}
再回想注解实质上是一个接口,它本身没有逻辑,那么它的值存在什么地方呢?那么答案就是Proxy实例中了。
这个Proxy实例有一个类型为AnnotationInvocationHandler的变量h,我回到上面创建Proxy对象的代码中,Proxy.newProxyInstance()的第三个参数就是InvocationHandler,而这个变量h就是它的实现类。
继续往变量h里看,它有一个字段memberValues,是一个map,而在这个map中,我发现了注解值存放的位置。key为注解的属性名,value就是属性值。
修改注解值
找到了注解值存放位置,那么修改就简单了
@Component
@Aspect
@Order(0)
public class InterestResolveELAspect {
@Around("@annotation(anno)")
public Object invoked(ProceedingJoinPoint pjp, Interest anno) throws Throwable {
// resolve spel
String key = resolve spel;
Boolean unless = resolve spel;
InvocationHandler h = Proxy.getInvocationHandler(anno);
Field hField = h.getClass().getDeclaredField("memberValues");
hField.setAccessible(true);
Map<String, Object> memberValues = (Map<String, Object>) hField.get(h);
memberValues.put("key", key);
memberValues.put("unless", unless.toString());
return pjp.proceed();
}
}
赶紧测试一下,看看InterestHandleAspect打印的内容是不是你想要的。。。。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【pandas】pandas中的常见函数
- 走进STL - 哈希表,散装称重么
- 第八届蓝桥杯省赛javaB组题目解析
- 拥抱STL - 类/结构体元素查询与排序
- 【tensorflow2.0】处理图片数据-cifar2分类
- 操作系统实验多线程编程中的读者优先和写者优先
- 【python】使用csv库以字典格式读写csv文件
- 基于TypeScript封装Axios笔记(八)
- springmvc之HttpMessageConverter<T>
- django-模板之静态文件加载(十四)
- springmvc之使用JstlView
- django-模板之include标签(十五)
- 【pytorch】改造mobilenet_v2进行multi-class classification(多标签分类)
- 走进STL - heap,小树芽
- 走进STL - 序列式容器(常用篇)