Spring基础之AOP和代理模式

文章目录

    • 理解AOP
      • AOP的实现原理
    • AOP代理模式
      • 静态代理
      • 动态代理
        • 1-JDK动态代理
        • 2-CGLIB动态代理
    • 总结

理解AOP

OOP - - Object Oriented Programming 面向对象编程
AOP - - Aspect Oriented Programming 面向切面编程
AOP是Spring提供的关键特性之一。AOP即面向切面编程,是OOP编程的有效补充。使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。从而避免了在业务逻辑的代码中混入了很多的系统性相关的逻辑–比如:事务管理、日志记录、权限管理等,从而达到了将不同的关注点分离出来松耦合的效果。

AOP的实现原理

AOP的实现原理就是代理模式----其关键点是AOP框架自动创建的AOP代理
AOP代理分为静态AOP代理和动态AOP代理:

  1. 静态AOP代理 –– 是指AspectJ实现的AOP代理,它是将切面代码直接编译到Java字节码文件中,发生在编译时。
  2. 动态AOP代理 –– 是指将切面代码进行动态织入实现的AOP代理,发生在运行时。Spring的AOP即为动态AOP实现技术为:JDK提供的动态代理技术和CGLIB(Code Generation Library动态字节码增强技术)。尽管实现技术不一样,但都是基于代理模式,都是生成一个代理对象。

AOP代理模式

代理模式的核心作用就是通过代理,控制对被代理的目标对象的访问。它的设计思路是:定义一个抽象角色{接口},让代理角色和真实角色分别去实现它。

真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。它只关注真正的业务逻辑。

代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并在前后可以附加自己的操作。
代理模式实现歌星演出场景

静态代理

要求被代理类和代理类同时实现相应的一套接口,通过代理类调用重写接口的方法,实际上调用的是原始对象的同样的方法。如下图

在这里插入图片描述

/*** 明星接口*/
public interface Star {void sing();
}
/*** 真实明星类*/
public class RealStar implements Star{@Overridepublic void sing() {System.out.println("明星本人开始唱歌...");}
}/*** 明星静态代理类*/
public class ProxyStar implements Star{private Star star; //接收明星对象/*** 通过构造方法传进来真实的明星对象* @param star*/public ProxyStar(Star star) {this.star = star;}@Overridepublic void sing() {System.out.println("明星代理先进行商务谈判...");//真实明星唱歌star.sing();System.out.println("明星演出完,代理收款...");}
}

这样的话,逻辑就非常清晰了。在代理类中,可以看到,维护了一个Star对象,通过构造方法传进来一个真实的Star对象给其赋值,
然后在唱歌这个方法里,使用真实对象来唱歌。所以说面谈、收钱都是由代理对象来实现的,唱歌是代理对象让真实对象来做。

/*** 测试客户端*/
public class TestClient {/*** 测试静态代理结果* @param args*/public static void main(String[] args) {Star realStar = new RealStar(); //创建真实对象Star proxy = new ProxyStar(realStar); //创建代理对象proxy.sing();}
}

静态代理的优缺点:
优点:
  1.被代理的业务类只需要做好自己的业务,实现了责任分离,保证了业务类的重用性
  2.将业务类隐藏起来,起到了保护作用
缺点:
  1.代理对象的某个接口只服务于某一个业务对象,每个真实对象都得创建一个代理对象
  2.如果接口增加一个方法,除了所有实现类需要实现这个方法外,代理类也需要实现,增加了代码的复杂度和成本

动态代理

在程序运行时由JVM通过反射机制动态的创建出代理对象的字节码。代理对象和真实对象的关系是在程序运行时才确定

1-JDK动态代理

JDK动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口来完成的,要使用JDK动态代理,必须要定义接口

API分析:
(1) java.lang.reflect.Proxy 类|-Java动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)
方法职责:为指定类加载器、一组接口及调用处理器  生成动态代理类实例 
参数:loader        :类加载器interfaces        :目标(真实)对象实现的接口hanlder        :代理执行处理器
返回:动态生成的代理对象
(2) java.lang.reflect.InvocationHandler接口:
public Object invoke(Object proxy, Method method, Object[] args)
方法职责:负责集中处理动态代理类上的所有方法调用
参数: proxy :  生成的代理对象method: 当前调用的真实方法对象args:    当前调用方法的实参
返回: 真实方法的返回结果
jdk动态代理操作步骤 实现InvocationHandler接口,创建自己增强代码的处理器。
② 给Proxy类提供ClassLoader对象和代理接口类型数组,创建动态代理对象。
③ 在处理器中实现增强操作。

示例:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** JDK动态代理处理类*/
public class JdkProxyHandler implements InvocationHandler {/*** 用来接收真实明星对象*/private Object realStar;/*** 传入真实明星对象,动态创建一个代理** @param realStar* @return*/public Object bind(Object realStar) {this.realStar = realStar;return Proxy.newProxyInstance(realStar.getClass().getClassLoader(),realStar.getClass().getInterfaces(), this);}/*** 当调用代理对象的方法时,会调用此方法** @param proxy* @param method* @param args* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("明星代理先进行谈判...");Object result = method.invoke(realStar, args); //真实对象明星唱歌System.out.println("演出完,代理收款...");return result;}
}
/*** 测试Jdk动态代理客户端*/
public class TestJdkProxyClient {public static void main(String[] args) {Star realStar = new RealStar(); //真实对象//创建一个代理对象实例Star proxy = (Star)new JdkProxyHandler().bind(realStar);//代理对象调用方法proxy.sing();}
}

相对于静态代理,JDK 动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度

2-CGLIB动态代理

由上面的分析可知,JDK 实现动态代理需要实现类通过接口定义业务方法,那对于没有接口的类,如何实现动态代理呢,这就需要 CGLIB 了。

  • CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类.
  • CGLIB动态代理是针对没有接口的类进行的代理,和JDK动态代理的区别是获取代理对象的方法不一样
/*** 真实明星类*/
public class RealStar{public void sing() {System.out.println("明星本人开始唱歌...");}
}import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** Cglib代理处理类*/
public class CglibProxyHandler implements MethodInterceptor {/*** 维护的目标对象*/private Object realStar;/***  Enhancer类是CGLIB中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展*/private Enhancer enhancer = new Enhancer();/*** 根据被代理对象的类型 ,动态创建一个代理对象* @param realStar* @return*/public Object bind(Object realStar){
this.realStar = realStar;enhancer.setSuperclass(realStar.getClass()); //使用增强器,设置被代理对象为父类enhancer.setCallback(this);  //设置回调方法,拦截器//动态创建一个代理类对象,并返回return enhancer.create();}/***  当调用代理对象的方法时,会调用此方法进行拦截* @param proxy 代理对象* @param method 需要增强的方法* @param objects 需要增强方法的参数* @param methodProxy  需要增强的方法的代理* @return 方法执行后的返回值* @throws Throwable*/@Overridepublic Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("代理明星先进行演出谈判...");//invokeSuper方法调用的对象已经是增强了Object result = methodProxy.invokeSuper(object,args); //明星唱歌System.out.println("演出完成,代理去收款...");return result;}
}/*** 测试Cglib动态代理客户端*/
public class TestCglibProxyClient {public static void main(String[] args) {RealStar realStar = new RealStar(); //真实对象//创建一个代理对象实例RealStar proxy = (RealStar) new CglibProxyHandler().bind(realStar);//代理对象调用方法proxy.sing();}
}

关于CGLIB 动态代理总结:

  • CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少,但是CGLIB 创建代理对象时所花费的时间却比JDK多得多,所以对于单例singleton的对象,因为无需频繁创建对象,用 CGLIB 合适,反之使用JDK方式要更为合适一些。
  • CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的,诸如private的方法也是不可以作为切面的。

小结
Spring AOP 中的代理使用逻辑:如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP;如果目标对象没有实现了接口,则采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 动态代理之间转换

总结

  • AOP面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
  • 使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。
  • Spring的AOP为动态AOP,实现的技术为: JDK提供的动态代理技术 和 CGLIB(动态字节码增强技术)
  • 代理模式--官方的定义为“为其他对象提供一种代理以控制对这个对象的访问”
  • java中有静态代理、JDK动态代理、CGLib动态代理的方式。静态代理指的是代理类是在编译期就存在的,相反动态代理则是在程序运行期动态生成的

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

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

相关文章

Jenkins邮件通知配置(7)

1、安装插件&#xff1a; Email Extension&#xff0c;Email Extension Template&#xff0c;这两个插件可以帮助我们进行邮件的编写发送以及格式化 2、配置jenkins中链接腾讯企业邮箱 先配置发送服务&#xff0c;然后在具体工程中设置接收者 基础信息&#xff1a; POP3/S…

SWIFT:自我认知微调

文档:https://github.com/modelscope/swift/blob/main/docs/source/LLM/%E8%87%AA%E6%88%91%E8%AE%A4%E7%9F%A5%E5%BE%AE%E8%B0%83%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5.md ​​​​​​代码: Swift是如何把自我认知数据集融合到训练集中呢? 1:相关的3个参数

企业级大数据安全架构(十一)Kerberos接入dophinscheduler

作者&#xff1a;楼高 建议将dophinscheduler集成到Ambari安装部署&#xff0c;在Ambari上面开启kerberos 1.安装准备 编译 从GitHub获取dolphinscheduler-1.3.9源码 git clone https://github.com/apache/dolphinscheduler.git -b 1.3.9-releasehttps://github.com/apache/…

多输入回归预测|GWO-CNN-LSTM|灰狼算法优化的卷积-长短期神经网络回归预测(Matlab)

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、算法介绍&#xff1a; 灰狼优化算法&#xff1a; 卷积神经网络-长短期记忆网络&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容…

ChatGPT/GPT4科研应用与AI绘图及论文写作

2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…

重看LeakCanary

LeakCanary是我很久之前看的东西了&#xff0c;我当时侯对它的印象就是它可以用来检测内存泄漏&#xff0c;具体原理就是将弱引用对象延迟个5s然后看是否被回收,如果没有被回收,那么就说明发生了内存泄漏,其他的也没有仔细地看 现在就详细地梳理一遍这个流程&#xff1a; 1.L…

微服务篇之分布式事务

一、Seata架构 Seata事务管理中有三个重要的角色&#xff1a; TC (Transaction Coordinator) - 事务协调者&#xff1a;维护全局和分支事务的状态&#xff0c;协调全局事务提交或回滚。 TM (Transaction Manager) - 事务管理器&#xff1a;定义全局事务的范围、开始全局事务、…

docker学习总结

docker 1.初识Docker1.1.什么是Docker1.1.1.应用部署的环境问题1.1.2.Docker解决依赖兼容问题1.1.3.Docker解决操作系统环境差异1.1.4.小结 1.2.Docker和虚拟机的区别1.3.Docker架构1.3.1.镜像和容器1.3.2.DockerHub1.3.3.Docker架构1.3.4.小结 1.4.安装Docker 2.Docker的基本操…

Kubernetes Prometheus 系列|Prometheus介绍和使用|Prometheus+Grafana集成

目录 第1章Prometheus 入门1.1 Prometheus 的特点1.1.1 易于管理1.1.2 监控服务的内部运行状态1.1.3 强大的数据模型1.1.4 强大的查询语言 PromQL1.1.5 高效1.1.6 可扩展1.1.7 易于集成1.1.8 可视化1.1.9 开放性 1.2 Prometheus 的架构1.2.1 Prometheus 生态圈组件1.2.2 架构理…

Go 数据库编程精粹:database/sql 实用技巧解析

Go 数据库编程精粹&#xff1a;database/sql 实用技巧解析 简介database/sql 库的基础知识核心概念连接池驱动事务 环境配置 建立数据库连接连接到数据库示例&#xff1a;连接 MySQL 数据库连接池管理 执行查询和处理结果基本查询执行多行查询执行单行查询 结果处理处理多行结果…

基于Java SSM框架实现问卷调查系统项目【项目源码】

基于java的SSM框架实现问卷调查系统演示 B/S结构 BROWSER/SERVER程序架构方式是使用电脑中安装的各种浏览器来进行访问和使用的&#xff0c;相比C/S的程序结构不需要进行程序的安装就可以直接使用。BROWSER/SERVER架构的运行方式是在远程的服务器上进行安装一个&#xff0c;然…

普中51单片机学习(DS1302)

DS1302时钟 DS1302实时时钟具有能计算2100年之前的秒、分、时、日、日期、星期、月、年的能力&#xff0c;还有闰年调整的能力。内部含有31个字节静态RAM&#xff0c;可提供用户访问。采用串行数据传送方式&#xff0c;使得管脚数量最少&#xff0c;简单SPI 3线接口。工作电压…

4.8 Verilog过程连续赋值

关键词&#xff1a;解除分配&#xff0c;强制&#xff0c;释放 过程连续赋值是过程赋值的一种。赋值语句能够替换其他所有wire 或 reg 的赋值&#xff0c;改写wire 或 reg 类型变量的当前值。 与过程赋值不同的是&#xff0c;过程连续赋值表达式能被连续的驱动到wire 或 reg …

C++——基础语法(2):函数重载

4. 函数重载 函数重载就是同一个函数名可以重复被定义&#xff0c;即允许定义相同函数名的函数。但是相同名字的函数怎么在使用的时候进行区分呢&#xff1f;所以同一个函数名的函数之间肯定是要存在不同点的&#xff0c;除了函数名外&#xff0c;还有返回类型和参数两部分可以…

本地配置多个git账户及ll设置

本地配置多个git账户 清除全局配置将命令行&#xff0c;切换到ssh目录生成GitLab和Gitee的公钥、私钥去对应的代码仓库添加 SSH Keys添加私钥ll设置 管理密钥验证仓库配置关于gitgitee.com: Permission denied (publickey) 清除全局配置 此步骤可以不做&#xff0c;经测试不影…

总结一下最近几个主界面

目前展示了用Avalonia做几个主要流行的主界面&#xff0c;演示了一下组件的使用。用不同的实现方式实现一些方法。 1、独立大屏展示&#xff0c;类似一个实时监控&#xff0c;这是一种目前很方便的大屏效果。 主要涉及的内内容&#xff1a; &#xff08;1&#xff09;窗标题实…

【视频编码\VVC】环路滤波基础知识

本文为新一代通用视频编码H.266\VVC原理、标准与实现的简化笔记。 定义&#xff1a;在视频编码过程中进行滤波&#xff0c;滤波后的图像用于后续编码。 目的&#xff1a;1、提升编码图像的质量。2、为后续编码图像提供高质量参考&#xff0c;获得更好的预测效果。 VVC中主要…

使用LinkedList实现堆栈及Set集合特点、遍历方式、常见实现类

目录 一、使用LinkedList实现堆栈 堆栈 LinkedList实现堆栈 二、集合框架 三、Set集合 1.特点 2.遍历方式 3.常见实现类 HashSet LinkedHashSet TreeSet 一、使用LinkedList实现堆栈 堆栈 堆栈&#xff08;stack&#xff09;是一种常见的数据结构&#xff0c;一端…

后端程序员入门react笔记(五)ajax请求

常见的ajax Ajax 最原始的方式&#xff0c;基于原生的jsXmlHttpRequest 多个请求之间如果有先后关系&#xff0c;会存在很多层回调的问题&#xff0c;也是基于原生jsJquery Ajax 基于原生XHR封装&#xff0c;依赖Jquery框架&#xff0c;由jquery 框架去封装原生的XML(Xml)封装…

【高德地图】Android高德地图控件交互详细介绍

&#x1f4d6;第5章 与地图控件交互 ✅控件交互&#x1f9ca;缩放按钮&#x1f9ca;指南针&#x1f9ca;定位按钮&#x1f9ca;地图Logo ✅手势交互&#x1f9ca;缩放手势&#x1f9ca;滑动手势&#x1f9ca;旋转手势&#x1f9ca;倾斜手势&#x1f9ca;指定屏幕中心点的手势操…