spring 18 动态通知调用

十念  金牌会员 | 2022-8-11 04:04:28 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 824|帖子 824|积分 2472

带参数绑定的通知方法调用

点击查看代码
  1. @Aspect
  2.     static class MyAspect {
  3.         @Before("execution(* foo(..))") // 静态通知调用,不带参数绑定,执行时不需要切点
  4.         public void before1() {
  5.             System.out.println("before1");
  6.         }
  7.         @Before("execution(* foo(..)) && args(x)") // 动态通知调用,需要参数绑定,执行时还需要切点对象
  8.         public void before2(int x) {
  9.             System.out.printf("before2(%d)%n", x);
  10.         }
  11.     }
  12.     static class Target {
  13.         public void foo(int x) {
  14.             System.out.printf("target foo(%d)%n", x);
  15.         }
  16.     }
  17.     @Configuration
  18.     static class MyConfig {
  19.         @Bean
  20.         AnnotationAwareAspectJAutoProxyCreator proxyCreator() {
  21.             return new AnnotationAwareAspectJAutoProxyCreator();
  22.         }
  23.         @Bean
  24.         public MyAspect myAspect() {
  25.             return new MyAspect();
  26.         }
  27.     }
  28.     public static void main(String[] args) throws Throwable {
  29.         GenericApplicationContext context = new GenericApplicationContext();
  30.         context.registerBean(ConfigurationClassPostProcessor.class);
  31.         context.registerBean(MyConfig.class);
  32.         context.refresh();
  33.         AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
  34.         List<Advisor> list = creator.findEligibleAdvisors(Target.class, "target");
  35.         Target target = new Target();
  36.         ProxyFactory factory = new ProxyFactory();
  37.         factory.setTarget(target);
  38.         factory.addAdvisors(list);
  39.         Object proxy = factory.getProxy(); // 获取代理
  40.         List<Object> interceptorList =
  41.                 factory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod(
  42.                         "foo", int.class), Target.class);
  43.         for (Object o : interceptorList) {
  44.             showDetail(o);
  45.         }
  46.         System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>");
  47.         ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(
  48.                 proxy, target, Target.class.getMethod("foo", int.class),
  49.                 new Object[]{100}, Target.class, interceptorList
  50.         ) {}; // spring 内部可以创建匿名子类来创建构造器 protected 的对象
  51.         invocation.proceed();
  52.         /*
  53.             学到了什么
  54.                 a. 有参数绑定的通知调用时还需要切点,对参数进行匹配及绑定
  55.                 b. 复杂程度高, 性能比无参数绑定的通知调用低
  56.          */
  57.     }
  58.     public static void showDetail(Object o) {
  59.         try {
  60.             Class<?> clazz = Class.forName("org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher");
  61.             if (clazz.isInstance(o)) {
  62.                 Field methodMatcher = clazz.getDeclaredField("methodMatcher");
  63.                 methodMatcher.setAccessible(true);
  64.                 Field methodInterceptor = clazz.getDeclaredField("interceptor");
  65.                 methodInterceptor.setAccessible(true);
  66.                 System.out.println("环绕通知和切点:" + o);
  67.                 System.out.println("\t切点为:" + methodMatcher.get(o));
  68.                 System.out.println("\t通知为:" + methodInterceptor.get(o));
  69.             } else {
  70.                 System.out.println("普通环绕通知:" + o);
  71.             }
  72.         } catch (Exception e) {
  73.             e.printStackTrace();
  74.         }
  75.     }
复制代码

  • 通过 proxyFactory 的 getInterceptorsAndDynamicInterceptionAdvice() 将其他通知统一转换为 MethodInterceptor 环绕通知
  • 所谓动态通知,体现在上面方法的 DynamicInterceptionAdvice 部分,这些通知调用时因为要为通知方法绑定参数,还需再次利用切点表达式
  • 动态通知调用复杂程度高,性能较低
”匿名子类写法“:

可参考:https://blog.csdn.net/weixin_39570751/article/details/121253167
点击查看代码
  1. class S18Bean1 {
  2.     public S18Bean1() {
  3.     }
  4.     public void add() {
  5.     }
  6. }
复制代码
  1. public class S18Bean2 {
  2.     public static void main(String[] args) {
  3.         S18Bean1 s18Bean3 = new S18Bean1() {
  4.         };
  5.         S18Bean1 s18Bean2 = new S18Bean1() {
  6.         };
  7.         System.out.println(s18Bean3.getClass().getName());
  8.         System.out.println(s18Bean2.getClass().getName());
  9.     }
  10. }
复制代码

在哪个类创建的就以哪个类开头加$数字再加一个空字符命名,Class类的 getSimpleName() 为空,所以真正的名字是空,是匿名的。点击查看代码

一个包下的字包不属于当前包,当前包中的 protect 成员不能被子包访问。
如果里面有个类有个 protect 修饰的构造器 在子包中访问不了,spring 内部就是通过这个办法创建它的子类调用

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

十念

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表