Spring之AOP源码解析(中)

news2024/11/17 0:22:13

前言

在上一篇文章中,我们讲解了Spring中那些注解可能会产生AOP动态代理,我们通过源码发现,完成AOP相关操作都和ProxyFactory这个类有密切关系,这一篇我们将围绕这个类继续解析

演示

作用

ProxyFactory采用策略模式生成动态代理对象,具体生成cglib动态代理还是jdk动态代理,是根据我们具体设置的内容所决定的,我们分别演示一下生成cglib动态代理和jdk动态代理两种情况。具体细节可以详细阅读DefaultAopProxyFactory的createAopProxy方法

生成cglib动态代理

package com.test.aop.test;

public class CglibTarget {
    public void doObject() {
        System.out.println("CglibTarget doObject");
    }
}
package com.test.aop.test;

import org.springframework.aop.framework.ProxyFactory;

public class CglibProxy {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new CglibTarget());
        CglibTarget proxy = (CglibTarget) proxyFactory.getProxy();
        proxy.doObject();
    }
}

我们可以发现最终是以cglib动态代理方式生成代理对象

 生成jdk动态代理

package com.test.aop.test;

public interface JdkTarget {
    void doObject();
}
package com.test.aop.test;

public class JdkTargetImpl implements JdkTarget {

    @Override
    public void doObject() {
        System.out.println("JdkTargetImpl doObject");
    }
}
package com.test.aop.test;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.SingletonTargetSource;

public class JdkProxy {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setInterfaces(JdkTarget.class);
        proxyFactory.setTargetSource(new SingletonTargetSource(new JdkTargetImpl()));
        JdkTarget proxy = (JdkTarget) proxyFactory.getProxy();
        proxy.doObject();

    }
}

我们可以发现最终是以jdk动态代理方式生成代理对象 

ProxyFactory源码解析

我们先观察一下ProxyFactory这个类的继承关系

我们以proxyFactory.getProxy()方法为切入口,进行源码解析 

对上述流程进行梳理,见下图

我们分别查看两种方式的代理过程

jdk动态代理过程(JdkDynamicAopProxy)

jdk动态代理的过程比较简单主要就是利用Proxy.newProxyInstance方法创建代理对象,会默认实现SpringProxy,Advised,DecoratingProxy三个接口

cglib动态代理过程(CglibAopProxy) 

cglib动态代理主要利用我们自定义的ProxyFactory对象,然后根据设置的参数构建Enhancer对象,然后创建代理对象。我们需要注意的是代理对象一共有七个拦截器,spring会根据我们调用的方法,指定拦截器。比如我们调用equal方法就会经过EqualsInterceptor拦截器,调用hashCode方法就会经过HashCodeInterceptor拦截器。我们主要需要关注的就是DynamicAdvisedInterceptor拦截器,除了equal、hashcode这些特殊的方法,普通方法一般都会经过这个拦截器。具体进入那个拦截器可以查看CglibAopProxy类的accept方法

cglib动态代理的对象会默认实现SpringProxy,Advised两个接口

ProxyFactory的重要属性Advisor

我们在前文中说到@EnableTransactionManagement,@EnableAspectJAutoProxy完成AOP动态代理都是依靠AbstractAutoProxyCreator的postProcessAfterInitialization方法中完成的,其中最主要的方法是wrapIfNecessary,我们查看相关源码

通过源码我们知道只有找到了,可以作用于当前bean的Advisor,spring才会进行动态代理

我们在上文中提到了@EnableTransactionManagement,@EnableAspectJAutoProxy两个注解的渊源,然后得出结论:如果同时存在,最终只能存在一个优先级更高的BeanPostProcessor(bpp)

那么@EnableAspectJAutoProxy这个注解注入了一个优先级更高的bpp,有什么扩展点呢?我们以上图中getAdvicesAndAdvisorsForBean方法为切入口进行分析

@EnableTransactionManagement注入的bpp没有重写findCandidateAdvisors方法,其查找Advisor的方法为父类的默认实现。@EnableAspectJAutoProxy注解注入的bpp重写了findCandidateAdvisors方法,其在父类方法的基础上又试图通过BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法寻找更多的Advisor,最后再判断这些找到的Advisors是否可以作用在当前bean,如果存在可以作用于当前bean的Advisors,则进行AOP动态代理

 总结

ProxyFactory这个类在Spring完成AOP动态代理的过程中起到了重要的作用,具体如下所述

  • 可以通过配置决定Spring进行aop动态代理的方式,比如将@EnableTransactionManagement注解的proxyTargetClass参数设置为true(不能保证一定进行cglib动态代理,具体可以查看DefaultAopProxyFactory的createAopProxy方法)
  • 可以设置监听器,监听动态代理对象
  • 可以决定是否提前暴露代理对象,比如将@EnableAspectJAutoProxy注解的exposeProxy参数设置为true,然后通过AopContext.currentProxy()就可以获取原始对象
  • 可以通过查找是否存在作用于指定bean的Advisors,来决定是否需要进行动态代理

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

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

相关文章

FairyGUI × Cocos Creator 3.x 使用方式

前言 上一篇文章 FariyGUI Cocos Creator 入门 简单介绍了FairyGUI,并且按照官方demo成功在Cocos Creator2.4.0上运行起来了。 当我今天使用Creator 3.x 再引入2.x的Lib时,发现出现了报错。 这篇文章将介绍如何在Creator 3.x上使用fgui。 引入 首先&…

想把握现货黄金价格走势 这两点能助你掌握优势

现货黄金价格走势很是狡猾,想要抓准它的波动是很难的。但我们作为投资者,偏要与它较劲。想要像捕捉猎物一样捕捉到现黄金价格走势,以下这两点投资者要注意。 了解清楚自己的风格适合什么市场?投资者有比较固定的投资风格&#xff…

Day4. 文件IO的基本概念和读写

温习&#xff1a; 文件的拷贝&#xff08;单个字符&#xff09;(fgetc/fputc) #include <stdio.h>int main(void) {FILE* fp NULL;FILE* fq NULL;char ch 0;fp fopen("str.txt","r");if (fp NULL){perror("file to fopen!");retur…

指南 | 从概念到实践:探索独立站在当代电商中的关键作用

搭建电商独立站指南 随着数字化时代的到来&#xff0c;电子商务已成为全球商业生态的核心组成部分。在这个不断变化的市场中&#xff0c;独立站作为企业建立在线身份和拓展业务的强大工具&#xff0c;正逐步展现出其不可替代的价值。 从概念到实践&#xff0c;本文将深入探索独…

1500W SMB TVS

TVS的简介 瞬态电压抑制二极管&#xff0c;简称TVS。当TVS两极受到反向瞬态高能量冲击时&#xff0c;它能以 10- s的速度&#xff0c;将其两极间的高阻抗变为低阻抗&#xff0c;吸收高达数千瓦的浪涌功率&#xff0c;使两极间的电压钳位于一个预定值&#xff0c;有效地保护电子…

Linux环境安装Git(详细图文)

说明 此文档Linux环境为&#xff1a;Ubuntu 22.04&#xff0c;本文档介绍两种安装方式&#xff0c;一种是服务器能联网的情况通过yum或apt命令下载&#xff0c;第二种采用源码方式安装。 一、yum/apt方式安装 1.yum方式安装Git 如果你的服务器环境是centos/redhot&#xff…

理论学习-ARM-内核

ARM内核 函数的调用加载、存储计算中断异常线程的切换注意事项参考文献 为了提高学习效率&#xff0c;我们要提前想好学习策略。 首先&#xff0c;使用频率越高的知识点&#xff0c;越要首先学习。假使&#xff0c;我们学习了一个知识点&#xff0c;能覆盖工作中80%的工作量&am…

Java Swing游戏开发学习1

不使用游戏引擎&#xff0c;只使用Java SDK开发游戏的学习。 游戏原理 图片来自某大佬视频讲解 原理结合实际代码 public class GamePanel extends Jpanel implements Runnable {...run(){}// 详情看下图... }项目结构 运行效果 代码code 在我的下载里面可以找到&#xf…

【MATLAB】EEMD_ MFE_SVM_LSTM 神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 EEMD_MFE_SVM_LSTM神经网络时序预测算法是一种结合了多种技术的复杂预测方法&#xff0c;旨在提高时序预测的准确性和稳定性。以下是对该算法的详细介绍&#xff1a; EEMD&#xff08;扩展…

VSCODE上使用python_Django_创建最小项目

接上篇 https://blog.csdn.net/weixin_44741835/article/details/136135996?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22136135996%22%2C%22source%22%3A%22weixin_44741835%22%7D VSCODE官网&#xff1a; Editing Python …

【DWRSeg】重新思考高效获取多尺度上下文信息以进行实时语义分割

目录 &#x1f436;&#x1f436;1.摘要 &#x1f42d;&#x1f42d; 2.设计动机 &#x1f439;&#x1f439; 3.区域残差和语义残差 &#x1f430;&#x1f430; 4.Dilation-wise Residual和Simple Inverted Residual &#x1f343; 4.1DWR &#x1f342; 4.2SIR &…

OpenGauss数据库本地搭建并结合内网穿透实现远程访问

文章目录 前言1. Linux 安装 openGauss2. Linux 安装cpolar3. 创建openGauss主节点端口号公网地址4. 远程连接openGauss5. 固定连接TCP公网地址6. 固定地址连接测试 前言 openGauss是一款开源关系型数据库管理系统&#xff0c;采用木兰宽松许可证v2发行。openGauss内核深度融合…

C语言的位操作 - bit 、byte的清零,置1,提取,判断

下面分享关于位操作的一些笔记&#xff1a; 一、位操作简单介绍 首先&#xff0c;以下是按位运算符&#xff1a; 在嵌入式编程中&#xff0c;常常需要对一些寄存器进行配置&#xff0c;有的情况下需要改变一个字节中的某一位或者几位&#xff0c;但是又不想改变其它位原有的值…

【Spring Cloud】实现微服务调用的负载均衡

文章目录 什么是负载均衡自定义实现负载均衡启动shop-product微服务通过nacos查看微服务的启动情况自定义实现负载均衡 基于Ribbon实现负载均衡添加注解修改服务调用的方法Ribbon支持的负载均衡策略通过修改配置来调整 Ribbon 的负载均衡策略通过注入Bean来调整 Ribbon 的负载均…

什么是nginx 、安装nginx

一、 什么是nginx 1.1 nginx的概念 一款高新能、轻量级Web服务软件系统资源消耗低对HTTP并发连接的处理能力高单台物理服务器可支持30 000&#xff5e;50 000个并发请求。 1.2 nginx模块与作用 核心模块&#xff1a;是 Nginx 服务器正常运行必不可少的模块&#xff0c;提供错…

FPGA OSERDESE2

Output Parallel-to-Serial Logic Resources (OSERDESE2) OSERDESE2 在Xilinx 7 系列器件是一款专用的并行至串行转换器,具有特定的时钟和逻辑资源,旨在促进高速源同步接口的实现。每个OSERDESE2模块都包括一个专用的数据串行器和 3 状态控制。数据和 3 态串行器都可以在 SD…

Vue 中 onclick和@click区别

文章目录 一、直接上结论二、验证代码&#xff0c;可直接运行三、点击结果 一、直接上结论 onclick 只能触发 js的原生方法&#xff0c;不能触发vue的封装方法click 只能触发vue的封装方法&#xff0c;不能触发js的原生方法 二、验证代码&#xff0c;可直接运行 <!DOCTYP…

数据的结构

数据结构介绍 数据结构是一门介于数学、计算机硬件和计算机软件三者之间的核心课程。数据结构不仅是一般程序设计的基础,而且是设计和实现编译程序、操作系统、数据库系统及其他系统程序和大型应用程序的重要基础。 数据结构研究的是数据对象内部各数据元素之间逻辑关系问题…

【C++练级之路】【Lv.8】【STL】list类的模拟实现

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C语言》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、结点二、迭代器2.1 成员变量与默认成员函数2.2 operator*2.3 operator->2.4 operator2.5 operator- …

Go语言中的TLS加密:深入crypto/tls库的实战指南

Go语言中的TLS加密&#xff1a;深入crypto/tls库的实战指南 引言crypto/tls库的核心组件TLS配置&#xff1a;tls.Config证书加载与管理TLS握手过程及其实现 构建安全的服务端创建TLS加密的HTTP服务器配置TLS属性常见的安全设置和最佳实践 开发TLS客户端应用编写使用TLS的客户端…