经过上一节的,我们可以自己解析spel表达式。那么我现在的想法是,在注解的第一层aop中解析spel,然后将解析后的值设置到属性中,那么在之后的aop中就不用解析了。
找出注解中值存放位置
继续上一节的代码,在上一节的AOP中添加注解@Order(0),再新增一个注解,添加@Order(1)。注意order这个注解有坑的,最好先百度完再使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Component @Aspect @Order(0) public class InterestResolveELAspect { }
@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类生一个代理对象,有这个代理对象去调用真实方法,就像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public interface A { String func1(); }
public class B implements A { @Override public String func1() { public String func2() { }
public static void main(String ...args) { B bInstance = new B(); B bProxy = Proxy.newProxyInstance( B.class.getClassLoader(), B.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke (Object proxy, Method method, Object[] args ) throws Throwable { System.out.println(String.format("调用 %s 之前", method.getName()));
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就是属性值。
修改注解值
找到了注解值存放位置,那么修改就简单了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Component @Aspect @Order(0) public class InterestResolveELAspect { @Around("@annotation(anno)") public Object invoked(ProceedingJoinPoint pjp, Interest anno) throws Throwable { 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打印的内容是不是你想要的。。。。