首页 > 其他分享 >静态通知调用

静态通知调用

时间:2023-01-25 20:00:11浏览次数:31  
标签:调用 target 静态 通知 Object System println new public

静态通知调用

目录

  • 适配器模式:不同通知统一转换为环绕通知
  • 无参数绑定通知链执行过程,责任链模式体现
  • 模拟实现MethodInvocation

适配器模式

上一章的Main方法里面创建Advisors方法可以抽象为以下几个方法,分别对应不同的AspectJMethodxxxxAdvice,然后将不同通知统一转化为环绕通知MethodInterceptor。

        // 切面实例工厂
        AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new A18Aspect());
        // 1. 获取相关通知
        List<Advisor> beforeAdvisors = getBeforeAdvisors(factory);
        List<Advisor> afterAdvisors = getAfterAdvisors(factory);
      // 2. 将相关通知统一转化为环绕通知MethodInterceptor
            A18Target target = new A18Target();

            ProxyFactory proxyFactory = new ProxyFactory();
            proxyFactory.setTarget(target);
            proxyFactory.addAdvisors(beforeAdvisors);

            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

            List<Object> methodInterceptors = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(A18Target.class.getMethod("foo"), A18Target.class);
            for (Object methodInterceptor : methodInterceptors) {
                System.out.println(methodInterceptor);
            }

为什么要转化

无论是ProxyFactory基于哪种方式创建代理,最后都要调用advice的都是MethodInvocation对象:
a. 因为Advisor有多个,且一个套一个调用,因此需要一个调用链对象,即MethodInvocation
b. MethodInvocation 要知道advice有哪些,还要知道目标,调用次序如下:

before1 -> before2 -> target -> after2 ->  after1

c. 从上图可以看出,环绕通知才适合作为advice,因此其他before,afterReturning,afterThrowing都会被转化为环绕通知
d. 统一转换为环绕通知,提现的是设计模式中的适配器模式

  • 对外是为了方便要区分before、afterReturing、afterThrowing
  • 对内都是使用环绕通知,统一使用MethodInterceptor表示

什么是适配器模式

以切面静态转换场景为例,通知会被转换为MethodInterceptor,而@Before这一类注解会被解析为AspectJMethodBeforeAdvice形式这样的另外一套接口。因此注解解析后的接口是不能直接使用的,我们需要把他统一转换为MethodInterceptor,而中间转换的类对象称之为适配器对象

org.springframework.aop.framework.adapter.AdvisorAdapter:

  1. MethodBeforeAdviceAdapter 将 @Before 的 AspectJMethodBeforeAdvice 适配为 MethodBeforeAdviceInterceptor
  2. AfterReturningAdviceAdapter 将 @AfterReturning AspectJAfterReturningAdvice 适配为 AfterReturningAdviceInterceptor

获取适配器的方式为:

            // 2. 将相关通知统一转化为环绕通知MethodInterceptor
            A18Target target = new A18Target();

            ProxyFactory proxyFactory = new ProxyFactory();
            // 准备把 MethodInvocation 放入通过advice的形式当前线程。(放在最外层)
            proxyFactory.addAdvice(0,ExposeInvocationInterceptor.INSTANCE);

            proxyFactory.setTarget(target);
            proxyFactory.addAdvisors(beforeAdvisors);

            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

            List<Object> methodInterceptors = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(A18Target.class.getMethod("foo"), A18Target.class);
            for (Object methodInterceptor : methodInterceptors) {
                System.out.println(methodInterceptor);
            }
           // 通过ProxyFactory.getInterceptorsAndDynamicInterceptionAdvice将相关通知统一转化为环绕通知MethodInterceptor
            A18Target target = new A18Target();

            ProxyFactory proxyFactory = new ProxyFactory();
            proxyFactory.setTarget(target);
            proxyFactory.addAdvisors(beforeAdvisors);

            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

            List<Object> methodInterceptors = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(A18Target.class.getMethod("foo"), A18Target.class);
            for (Object methodInterceptor : methodInterceptors) {
                System.out.println(methodInterceptor);
            }

调用链执行

            // 3. 创建执行调用链(组成:环绕通知s + 目标信息)
            // 3.1 准备调用链(package org.springframework.aop.framework;)
            MethodInvocation methodInvocation = new ReflectiveMethodInvocation(
                    null,
                    target,
                    A18Target.class.getMethod("foo"),
                    new Object[0],
                    A18Target.class,
                    methodInterceptors
            );
            // 3.2 调用调用链
            methodInvocation.proceed();

实现责任链模式:


public class A18_1 {

    static class A18_1Aspect {
        @Before("execution(* foo()) ")
        public void before() {
            System.out.println("before1");
        }

        @Before("execution (* foo())")
        public void before2() {
            System.out.println("before2");
        }

        public void after() {
            System.out.println("after");
        }

        public void afterReturning() {
            System.out.println("afterReturning");
        }
    }

    static class A18_1Target {
        public void foo() {
            System.out.println("target.foo");
        }
    }

    static class A18_1Advice1 implements MethodInterceptor {

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Advice1 before()");
            Object proceed = invocation.proceed();
            System.out.println("Advice1 after()");
            return proceed;
        }
    }

    static class A18_1Advice2 implements MethodInterceptor {

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Advice2 before()");
            Object proceed = invocation.proceed();
            System.out.println("Advice2 after()");
            return proceed;
        }
    }

    /**
     * 1. 把必要信息存储在 invocation 中:target、
     * 2.
     */
    static class MyInvocation implements MethodInvocation {
        // 目标对象
        private Object target;
        // 目标方法
        private Method method;
        // 目标方法的参数
        private Object[] params;
        // 环绕通知的list
        private List<MethodInterceptor> methodInterceptorList;

        private int curInterceptorIndex = -1;

        public MyInvocation(Object target, Method method, Object[] params, List<MethodInterceptor> methodInterceptorList) {
            this.target = target;
            this.method = method;
            this.params = params;
            this.methodInterceptorList = methodInterceptorList;
        }

        @Override
        public Method getMethod() {
            return method;
        }

        @Override
        public Object[] getArguments() {
            return params;
        }

        @Override
        public Object proceed() throws Throwable {
            // 调用每一个环绕通知 和 目标
            if (curInterceptorIndex == methodInterceptorList.size() - 1) {
                return method.invoke(target, params);
            }
            MethodInterceptor curMethodInterceptor = methodInterceptorList.get(++this.curInterceptorIndex);
            return curMethodInterceptor.invoke(this);
        }

        @Override
        public Object getThis() {
            // 返回目标对象
            return target;
        }

        @Override
        public AccessibleObject getStaticPart() {
            // todo
            return method;
        }
    }


    public static void main(String[] args) throws Throwable {
        A18_1Target target = new A18_1Target();
        A18_1Advice1 advice1 = new A18_1Advice1();
        A18_1Advice2 advice2 = new A18_1Advice2();
        List<MethodInterceptor> methodInterceptors = Lists.newArrayList(advice2, advice1);
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(target);
        MyInvocation invocation = new MyInvocation(
                target,
                A18_1Target.class.getMethod("foo"),
                new Object[0],
                methodInterceptors
        );
        invocation.proceed();
    }
}

标签:调用,target,静态,通知,Object,System,println,new,public
From: https://www.cnblogs.com/SsoZhNO-1/p/12409070.html

相关文章

  • Day15 - Http协议和静态服务器
    1.http介绍HTTP协议的介绍HTTP协议的全称是(HyperTextTransferProtocol),翻译过来就是超文本传输协议。超文本是超级文本的缩写,是指超越文本限制或者超链接,比如:......
  • 静态Web服务器-多任务版Python解释器详解实现代理池的API模块
    学习目标能够写出多线程版的多任务web服务器程序1.静态Web服务器的问题目前的Web服务器,不能支持多用户同时访问,只能一个一个的处理客户端的请求,那么如何开发多任务版的web......
  • delphi通过方法名调用方法
    delphi通过方法名调用方法unitUnit1;interfaceusesWinapi.Windows,Winapi.Messages,System.SysUtils,System.Variants,System.Classes,Vcl.Graphics,Vcl......
  • bat批处理实现飞书机器人告警通知 — WGCLOUD
    1、在群聊中添加机器人进入群聊,打开群设置,找到群机器人,并点击添加机器人。选择自定义机器人加入群聊。 添加该机器人进群,设置机器人头像、名称和描述(随便写就可以了),然......
  • Python3配合Django来调用钉钉在线api实时监测员工考勤打卡情况
    基本上钉钉(dingding)作为一个远程办公平台来用的话,虽然差强人意,但是奈何市面上没有啥更好的选择,矬子里拔将军,也还是可以凑合用的,不过远程办公有个问题,就是每天需要检查员......
  • nginx索引静态文件
    前言针对nas服务器文件下载或者需要索引一些静态二进制文件的地方,可以利用nginx自带的索引文件功能实现。root/var/www/html;#索引目录autoindexon;autoindex_exact_......
  • nginx索引静态文件
    前言针对nas服务器文件下载或者需要索引一些静态二进制文件的地方,可以利用nginx自带的索引文件功能实现。root/var/www/html;#索引目录autoindexon;autoindex_exact......
  • 02 方法的调用和定义
    方法的调用和定义代码packagecom.zhan.base_3;publicclassTest01_Method{//修饰符返回值类型(void),表示没有返回值方法名(参数){方法体}//main......
  • SpringBoot静态资源映射
    Springboot添加静态资源映射配置将静态资源解析到指定的路径上@Slf4j@ConfigurationpublicclassWebMvcConfigextendsWebMvcConfigurationSupport{@Override......
  • Wallpaper Engine壁纸提取工具,pkg文件提取静态图片,pkg文件转jpg,pkg文件转png,pkg文件转
    遇到喜欢的Wallpaper壁纸,我们怎么能将壁纸保存成静态壁纸呢?Wallpaper壁纸和一般的壁纸是不一样的,它不是简单的图像文件,那么提取Wallpaper壁纸就需要一些小工具的帮助,目前使......