spring原理(第十天)

news2024/12/31 3:57:53

jdk 和 cglib 在 Spring 中的统一

Spring 中对切点、通知、切面的抽象如下

  • 切点:接口 Pointcut,典型实现 AspectJExpressionPointcut

  • 通知:典型接口为 MethodInterceptor 代表环绕通知

  • 切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut

两个切面概念
            aspect =
                通知1(advice) +  切点1(pointcut)
                通知2(advice) +  切点2(pointcut)
                通知3(advice) +  切点3(pointcut)
                ...
            advisor = 更细粒度的切面,包含一个通知和切点

模拟advisor底层实现

1.引入依赖

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

2.备好类(其中target1实现了I1接口)

 interface I1 {
        void foo();

        void bar();
    }

    static class Target1 implements I1 {
        public void foo() {
            System.out.println("target1 foo");
        }

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

    static class Target2 {
        public void foo() {
            System.out.println("target2 foo");
        }

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

3.创建切面

       //创建切点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");
        //创建通知
        MethodInterceptor methodInterceptor = invocation -> {
            System.out.println("before.....");
            Object result = invocation.proceed();
            System.out.println("after.....");
            return result;
        };
        //创建切面
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, methodInterceptor);
        //创建代理
        Target1 target = new Target1();
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(target);
        factory.addAdvisor(advisor);
        factory.setInterfaces(target.getClass().getInterfaces());
        factory.setProxyTargetClass(false);
        I1 proxy = (I1) factory.getProxy();
        System.out.println(proxy.getClass());
        proxy.foo();
        proxy.bar();

解释:

首先我们需要准备切点用pointcut子接口来创建,创建好了要设置他的切点表达式,用来指定,

其次我们需要创建通知,利用methodintercepter创建,他与之前我们创建代理是的名称一样,但包不一样,这个通知实际上是一个环绕通知。

准备好前两个了,我们就需要开始准备切面, 利用DefaultPointcutAdvisor创建该切面

最后创建代理对象用来增强,我们使用一个代理工厂来创建代理,他会根据条件自动选择代理模式

先创建出目标类对象,把切面添加到工厂等等,获取代理对象,最后调用方法

可以看到代理工厂选择了jdk代理,

创建代理有三种情况:

                a. proxyTargetClass = false, 目标实现了接口, 用 jdk 实现
                b. proxyTargetClass = false,  目标没有实现接口, 用 cglib 实现
                c. proxyTargetClass = true, 总是使用 cglib 实现

我们演示第二种,只需把目标类改成target2 ,以及生成的代理对象也改成target2

可以看到代理对象选择了cglib实现

  • AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现

  • AopProxy 通过 getProxy 创建代理对象

  • 图中 Proxy 都实现了 Advised 接口,能够获得关联的切面集合与目标(其实是从 ProxyFactory 取得)

  • 调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor

学到了什么
                a. Spring 的代理选择规则
                b. 底层的切点实现
                c. 底层的通知实现
                d. ProxyFactory 是用来创建代理的核心实现, 用 AopProxyFactory 选择具体代理实现
                    - JdkDynamicAopProxy
                    - ObjenesisCglibAopProxy

切点匹配

1.准备类(在某些方法和类上添加注解,模拟切点如何匹配注解)

  static class T1 {
        @Transactional
        public void foo() {
        }
        public void bar() {
        }
    }

    @Transactional
    static class T2 {
        public void foo() {
        }
    }

    @Transactional
    interface I3 {
        void foo();
    }
    static class T3 implements I3 {
        public void foo() {
        }
    }

2.通过AspectJExpressionPointcut创建切点,并设置切点表达,一开始我们设置成根据全类名

3.利用matches方法判断是否匹配成功

代码如下:

        AspectJExpressionPointcut pt1 = new AspectJExpressionPointcut();
        pt1.setExpression("execution(* bar())");
        System.out.println(pt1.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pt1.matches(T1.class.getMethod("bar"), T1.class));

可以看到bar方法匹配成功 

 

 根据注解来设置切点表达,判断是否匹配

        AspectJExpressionPointcut pt2 = new AspectJExpressionPointcut();
        pt2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");
        System.out.println(pt2.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pt2.matches(T1.class.getMethod("bar"), T1.class));

可以看到添加了注解的foo方法成功匹配 

 

 自定义切点匹配

利用StaticMethodMatcherPointcut来创建切点,重写里面的方法实现自定匹配规则(MergedAnnotations)

        StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                // 检查方法上是否加了 Transactional 注解
                MergedAnnotations annotations = MergedAnnotations.from(method);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }
                // 查看类上是否加了 Transactional 注解
                annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }
                return false;
            }
        };

        System.out.println(pt3.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pt3.matches(T1.class.getMethod("bar"), T1.class));
        System.out.println(pt3.matches(T2.class.getMethod("foo"), T2.class));
        System.out.println(pt3.matches(T3.class.getMethod("foo"), T3.class));

通过设置MergedAnnotations.SearchStrategy.TYPE_HIERARCHY,可以实现实现的接口上添加了注解也能匹配

 

可以看到只有t1类中bar方法没有添加注解,所以没有匹配成功

学到了什么
                a. 底层切点实现是如何匹配的: 调用了 aspectj 的匹配方法
                b. 比较关键的是它实现了 MethodMatcher 接口, 用来执行方法的匹配
 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1984389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

政务服务技能竞赛规则流程方案

此次政务服务技能竞赛以“强服务、优素质、促提升、共发展”为目标&#xff0c;通过以赛代练、以赛促建、比学赶超、全面提升&#xff0c;激发各级政务服务工作人员学政策、钻业务、练技能的热情和积极性&#xff0c;全面推动行政效能提升与营商环境建设&#xff0c;铸造新时代…

pytorch和deep learning技巧和bug解决方法短篇收集

有一些几句话就可以说明白的观点或者解决的的问题&#xff0c;小虎单独收集到这里。 torch.hub.load how does it work 下载预训练模型再载入&#xff0c;用程序下载链接可能失效。 model torch.hub.load(ultralytics/yolov5, yolov5s)model torch.hub.load(ultralytics/y…

IROS2024 | DarkGS:学习神经照明和3D高斯重新照明,用于黑暗中机器人探索

DarkGS&#xff1a;学习神经照明和3D高斯重新照明&#xff0c;用于黑暗中机器人探索 论文标题&#xff1a;DarkGS: Learning Neural Illumination and 3D Gaussians Relighting for Robotic Exploration in the Dark 论文地址&#xff1a;https://arxiv.org/abs/2403.10814 研…

数据开发/数仓工程师上手指南(七)CDM-DWS层搭建规范及流程

前言 进入到了CMD公共数据层的结尾最后一层-DWS层了&#xff0c;该层基本就是直接与业务强关联&#xff0c;也就是说产品提出的需求&#xff0c;或是报表、用户画像统计好还是数据大屏都是在这一层给处理好数据&#xff0c;再放入ADS层&#xff0c;然后我们只需要在BI里面配备…

【数据结构】——堆的实现(赋源码)

堆的概念与结构 堆(Heap)是计算机科学中一类特殊的数据结构&#xff0c;是最高效的优先级队列。堆通常是一个可以被看作一棵完全二叉树的数组对象。 堆的性质: 堆中某个结点的值总是不大于或不小于其父结点的值&#xff1b; 堆总是一棵完全二叉树。 堆的物理结构本质上是顺序…

PDF怎么转Word?分享二个简单的方法

很多小伙伴在工作学习的时候&#xff0c;经常会遇到别人发来的PDF文件。PDF 文件用于查看资料非常方便&#xff0c;因为它们的布局稳定&#xff0c;在大多数设备上都可以显示相同的布局。 如果我们需要将其转换为Word&#xff0c;如何转换呢&#xff1f;许多人不知道如何转换。…

怎么录制视频?简单步骤教你如何录制高质量视频

视频是我们生活、工作和学校中不可或缺的一部分&#xff0c;但对于初学者来说&#xff0c;面对琳琅满目的录屏工具&#xff0c;往往感到无从下手&#xff0c;今天我们就给大家分享几种简单又高效的电脑录屏方法&#xff0c;让你轻松掌握高质量视频录制的技巧。 录制技巧1&#…

工厂人员定位系统原理

工厂人员定位系统是一种通过现代无线通讯技术和定位技术实现对工厂内人员位置进行实时监测的系统。其具体原理是通过安装在员工身上的定位标签产生无线电信号&#xff0c;并通过无线通讯网络传输给基站&#xff0c;再由基站将数据传输到服务器进行处理&#xff0c;最终在监控中…

《藏文驾考》App:支持藏汉双语切换的驾考题库,方便不熟汉语的藏族学员考驾照,中文藏文语音读题!

藏文驾考&#xff0c;是一款支持藏汉双语切换的驾照考试在线刷题学习软件。服务于涉藏地区的藏文驾驶理论考试&#xff0c;同步西藏、四川、青海、甘南等涉藏地区的驾考新规题库。提供科目一、科目四藏文交规理论学习&#xff0c;科目二、科目三视频技巧讲解。支持汉语、卫藏、…

Power功效分析之广义模型原理及案例实操

Power功效分析常用于实验研究时样本量的计算&#xff08;或功效值计算&#xff09;&#xff0c;如果是涉及广义模型时的回归系数差异计算时&#xff0c;SPSSAU共提供二元logit回归和Poisson回归情况时的Power功效分析&#xff0c;具体如下表格所述&#xff1a; 比如二元Logit回…

监听器Listener + 过滤器Filter

监听器Listener 介绍 Listener是JavaEE的规范&#xff0c;就是接口 监听器的作用是&#xff0c;监听某种变化(一般就是对象创建/销毁, 属性变化), 触发对应方法完成相应的任务 ServletContextListener监听器&#xff08;最常用&#xff09; 作用&#xff1a; 监听S…

javase综合案例4 -- 考试系统

文章目录 一&#xff0c;项目要求二&#xff0c;创建实体类ExamItem三&#xff0c;创建考试服务类ExamService3.1 全局变量 考题列表itemList(List< ExamItem >类型)&#xff0c;答案数组answerArr (String[]类型)&#xff0c;得分score3.2 初始化方法init()3.3 打印菜单…

从0开始的算法(数据结构和算法)基础(六)

二叉树 什么是二叉树 二叉树是一种非线性数据结构(层次关系结构)&#xff0c;代表“祖先”与“后代”之间的派生关系&#xff0c;体现了“一分为二”的分治逻辑。与链表类似&#xff0c;二叉树的基本单元是节点&#xff0c;每个节点包含值、左子节点引用和右子节点引用。 首先…

人生苦短,我用 Python,AI 模型助力高效数据提取

一、前言 在网络爬虫和数据挖掘领域&#xff0c;提取网页内容是一项常见且重要的任务。无论是从新闻网站、电商平台还是社交媒体&#xff0c;获取有用的信息都是开展后续分析和应用的前提。然而&#xff0c;传统的网页内容提取需要编写大量的代码来处理和解析 HTML 文档&#…

comfyui flux

下载文本编码器&#xff0c;模型放到ComfyUI/models/clip/ 下&#xff0c;t5模型可以任选其一&#xff1b;https://huggingface.co/comfyanonymous/flux_text_encoders/tree/main 下载vae模型&#xff0c;https://huggingface.co/black-forest-labs/FLUX.1-schnell/tree/main&a…

31、Python之面向对象:开闭原则与多态?学我者生、似我者死

引言 前面我们花了不少的篇幅把Python中面向对象的封装与继承简单介绍了一遍。今天来聊一下Python面向对象的第三个特性&#xff1a;多态。 其实&#xff0c;在《Python之面向对象&#xff1a;一切皆对象&#xff0c;可你真的需要面向对象吗》这篇文章中&#xff0c;对比面向…

Python大数据分析——朴素贝叶斯模型

Python大数据分析——朴素贝叶斯模型 数学方面思路理论基础高斯贝叶斯分类器多项式贝叶斯分类器伯努利贝叶斯分类器 代码部分高斯贝叶斯——皮肤识别多项式贝叶斯——毒蘑菇识别伯努利贝叶斯——情感分析 数学方面 思路 该分类器的实现思想非常简单&#xff0c;即通过已知类别…

vs code 代码同步到服务器,无需下载插件,使用自带ftp

可使用 vscode 自带ftp,无需下载插件 快捷键 ctrl shift p {"name": "My Server", //上传名"host": "192.168.56.102",//服务器"protocol": "ftp",//协议"port": 21,//端口"username": &q…

《机电信息》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问&#xff1a;《机电信息》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《机电信息》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;江苏省设备成套股份有限公司 主办单位&#x…

nvm安装高版本的node18.17.0,报https://nodejs.org/dist/latest/SHASUMS256.txt

1、执行npm install v18.17.0这条命令时&#xff0c;报如下错误&#xff1a; 2、或者报Node.js v18.17.0 is not yet released or is not available. 解决方案&#xff1a; 1、打开nvm 的安装路径中的setting.json node_mirror:npm.taobao.org/mirrors/node/ npm_mirror:npm.…