【JavaEE进阶】 代理模式

文章目录

  • 🍃前言
  • 🎋什么叫代理模式
  • 🌴静态代理
  • 🎍动态代理
    • 🚩JDK动态代理
    • 🚩CGLIB动态代理
  • ⭕总结

🍃前言

前面对Spring AOP的详细使用进行了介绍,这篇博客博主将详细讲解一下Spring AOP的原理,也就是Spring是如何实现AOP的.

Spring AOP是基于动态代理来实现AOP的,动态代理又是代理模式的一种

接下来我们一起来看看代理模式

🎋什么叫代理模式

代理模式,也叫委托模式.

定义:为其他对象提供⼀种代理以控制对这个对象的访问.它的作⽤就是通过提供⼀个代理类,让我们
在调⽤⽬标⽅法的时候,不再是直接对目标⽅法进行调用,而是通过代理类间接调用.

在某些情况下,⼀个对象不适合或者不能直接引⽤另⼀个对象,而代理对象可以在客⼾端和目标对象之
间起到中介的作用

使用代理前:
在这里插入图片描述
使用代理后:
在这里插入图片描述

生活中其实也存在着代理模式:

  • 艺人经纪⼈:光告商找艺⼈拍⼴告,需要经过经纪⼈,由经纪⼈来和艺⼈进行沟通.

  • 房屋中介:房屋进行租赁时,卖⽅会把房屋授权给中介,由中介来代理看房,房屋咨询等服务.

  • 经销商:⼚商不直接对外销售产品,由经销商负责代理销售.

  • 秘书/助理:合作伙伴找⽼板谈合作,需要先经过秘书/助理预约.

接下来我们来一起认识一下代理模式里的主要角色

  1. Subject:业务接⼝类.可以是抽象类或者接⼝(不⼀定有)

  2. RealSubject:业务实现类.具体的业务执⾏,也就是被代理对象.

  3. Proxy:代理类.RealSubject的代理

如果看成祖房

Subject:就是提前定义了房东做的事情,交给中介代理,也是中介要做的事情
RealSubject:房东
Proxy:中介

在这里插入图片描述

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行⼀些功能的附加与增强.

根据代理的创建时期,代理模式分为静态代理动态代理.

  • 静态代理:由程序员创建代理类或特定⼯具⾃动⽣成源代码再对其编译,在程序运⾏前代理类的
    .class⽂件就已经存在了.
  • 动态代理:在程序运⾏时,运⽤反射机制动态创建⽽成.

🌴静态代理

静态代理: 在程序运⾏前,代理类的.class⽂件就已经存在了.(在出租房⼦之前,中介已经做好了相关的
⼯作,就等租⼾来租房⼦了)

虽然静态代理也完成了对目标对象的代理,但是由于代码都写死了,对⽬标对象的每个⽅法的增强都是⼿动完成的,⾮常不灵活.所以⽇常开发⼏乎看不到静态代理的场景

如果目标对象新增其他业务,则需要我们手动进行修改,同样的,如果有新增接(Subject)和业务实现类(RealSubject),也需要对每⼀个业务实现类新增代理类(Proxy).

既然代理的流程是⼀样的,有没有⼀种办法,让他们通过⼀个代理类来实现呢?

这就需要⽤到动态代理技术了

🎍动态代理

相比于静态代理来说,动态代理更加灵活.

我们不需要针对每个目标对象都单独创建⼀个代理对象,而是把这个创建代理对象的⼯作推迟到程序运
行时由JVM来实现.也就是说动态代理在程序运行时,根据需要动态创建⽣成.

比如房屋中介,我不需要提前预测都有哪些业务,而是业务来了我再根据情况创建.

Java也对动态代理进⾏了实现,并给我们提供了⼀些API,常见的实现方式有两种:

  1. JDK动态代理

  2. CGLIB动态代理

🚩JDK动态代理

JDK动态代理类实现步骤

  1. 定义⼀个接⼝及其实现类(静态代理中的 HouseSubject 和 RealHouseSubject )
  2. ⾃定义 InvocationHandler 并重写 invoke ⽅法,在 invoke ⽅法中我们会调⽤⽬标⽅
    法(被代理类的⽅法)并⾃定义⼀些处理逻辑
  3. 通过 javaProxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) ⽅法创建代理对象

下面我们来进行实现以下:

  1. 定义JDK动态代理类

实现 InvocationHandler 接⼝

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class JDKInvocationHandler implements InvocationHandler {//⽬标对象即就是被代理对象private Object target;public JDKInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Thro
// 代理增强内容
System.out.println("我是中介, 开始代理");//通过反射调⽤被代理类的⽅法Object retVal = method.invoke(target, args);
//代理增强内容
System.out.println("我是中介, 代理结束");
return retVal;
}
}
  1. 创建⼀个代理对象并使用
public class DynamicMain {public static void main(String[] args) {HouseSubject target= new RealHouseSubject();
//创建⼀个代理类:通过被代理类、被代理实现的接⼝、⽅法调⽤处理器来创建HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[]{HouseSubject.class},new JDKInvocationHandler(target));proxy.rentHouse();}
}

对上述代码做一个简单的讲解:

  • InvocationHandler接是Java动态代理的关键接⼝之⼀,它定义了⼀个单⼀⽅法 invoke() ,用于处理被代理对象的方法调用.通过实现 InvocationHandler 接⼝,可以对被代理对象的方法进⾏功能增强.
  • Proxy 类中使⽤频率最高的⽅法是: newProxyInstance() ,这个⽅法主要⽤来⽣成⼀个代理对象
  • 这个⽅法⼀共有3个参数:
    • Loader:类加载器,⽤于加载代理对象.
    • interfaces:被代理类实现的⼀些接⼝(这个参数的定义,也决定了JDK动态代理只能代理实现了接⼝的⼀些类)
    • h:实现了InvocationHandler接⼝的对象

🚩CGLIB动态代理

JDK 动态代理有⼀个最致命的问题是其只能代理实现了接⼝的类.

有些场景下,我们的业务代码是直接实现的,并没有接⼝定义.为了解决这个问题,我们可以⽤CGLIB动
态代理机制来解决.

CGLIB(Code Generation Library)是⼀个基于ASM的字节码⽣成库,它允许我们在运⾏时对字节码进⾏
修改和动态⽣成.CGLIB通过继承⽅式实现代理,很多知名的开源框架都使⽤到了CGLIB.

例如:Spring中的AOP模块中:如果⽬标对象实现了接⼝,则默认采⽤JDK动态代理,否则采⽤CGLIB动态代理.

CGLIB动态代理类实现步骤

  1. 定义⼀个类(被代理类)
  2. ⾃定义 MethodInterceptor 并重写 intercept ⽅法, intercept ⽤于增强⽬标⽅法,和JDK动态代理中的 invoke ⽅法类似
  3. 通过Enhancer类的create()创建代理类

接下来一起来看一下实一个简单的实现:

  1. 添加依赖

和JDK动态代理不同,CGLIB(Code Generation Library)实际是属于⼀个开源项⽬,如果你要使用它
的话,需要⼿动添加相关依赖

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
  1. ⾃定义MethodInterceptor(⽅法拦截器)

实现MethodInterceptor接口

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLIBInterceptor implements MethodInterceptor {//⽬标对象, 即被代理对象private Object target;public CGLIBInterceptor(Object target){this.target = target;}@Overridepublic Object intercept(Object o, Method method, Object[] objects,MethodProxy methodProxy) throws Throwable {
// 代理增强内容System.out.println("我是中介, 开始代理");
//通过反射调⽤被代理类的⽅法Object retVal = methodProxy.invoke(target, objects);
//代理增强内容System.out.println("我是中介, 代理结束");return retVal;}
}
  1. 创建代理类,并使用
public class DynamicMain {public static void main(String[] args) {HouseSubject target= new RealHouseSubject();HouseSubject proxy= (HouseSubject)Enhancer.create(target.getClass(),new CGLIBInterceptor(target));proxy.rentHouse();}
}

代码简单讲解如下:

  • MethodInterceptor 和JDK动态代理中的 InvocationHandler 类似,它只定义了⼀个方法 intercept() ,用于增强目标⽅法
  • Enhancer.create()用来⽣成⼀个代理对象
  • 参数说明:
    • type:被代理类的类型(类或接⼝)
    • callback:自定义⽅法拦截器MethodInterceptor

⭕总结

关于《【JavaEE进阶】 代理模式》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

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

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

相关文章

(面试题)数据结构:链表相交

问题&#xff1a;有两个链表&#xff0c;如何判断是否相交&#xff0c;若相交&#xff0c;找出相交的起始节点 一、介绍 链表相交&#xff1a; 若两个链表相交&#xff0c;则两个链表有共同的节点&#xff0c;那从这个节点之后&#xff0c;后面的节点都会重叠&#xff0c;知道…

怎么把人物从图中抠出?分享几种好用的抠图方法

在日常生活中&#xff0c;我们时常需要将人物从繁杂的背景中优雅地提取出来&#xff0c;无论是为了制作一张精美的证件照&#xff0c;还是为了设计一幅引人注目的海报或宣传画。然而&#xff0c;对于许多非专业人士来说&#xff0c;这仿佛是一场与细节的捉迷藏游戏&#xff0c;…

Laravel Octane 和 Swoole 协程的使用分析二

又仔细研究了下 Octane 源码和 Swoole 的文档&#xff0c;关于前几天 Laravel Octane 和 Swoole 协程的使用分析中的猜想&#xff0c;得到进一步验证&#xff1a; Swoole 的 HTTP Server 启动后会创建一个 master 进程和一个 manager 进程&#xff1b;master 进程又会创建多个…

Python——Windows使用Nuitka2.0打包(保姆级教程)

目录 一、Python虚拟环境搭建 1.1、下载Python 1.2、使用 venv方法&#xff08;创建虚拟环境&#xff09; 1.3、进入虚拟环境 1.4、用pip下载项目需要的包&#xff08;与nuitka&#xff09; 二、 使用 Nuitka 打包 2.1、打包常用命令&#xff08;使用nuitka --help可查看所…

2024最新版聚合支付彩虹易支付PHP源码

彩虹易支付是一种便捷的支付解决方案&#xff0c;属于聚合易支付平台的一部分。它提供了即时到账功能&#xff0c;无需签约即可使用。通过这个平台&#xff0c;您可以方便地接入多种支付方式&#xff0c;包括支付宝当面付、QQ钱包、财付通、微信扫码支付和个体商户聚合收款码等…

内网渗透-DC-9靶机渗透

攻击机&#xff1a;kali 192.168.236.137 目标机&#xff1a;dc-9 192.168.236.138 一、信息收集 1.使用arp-scan -l和nmap进行主机发现和端口信息收集 nmap -sS -T5 --min-rate 10000 192.168.236.138 -sC -p- 发现22端口被阻塞 2.whatweb收集一下cms指纹信息 what http…

代码随想录算法训练营第62/63天| 503.下一个更大元素II、42. 接雨水、84.柱状图中最大的矩形

文章目录 503.下一个更大元素II思路代码 42. 接雨水思路代码 84.柱状图中最大的矩形思路代码 503.下一个更大元素II 题目链接&#xff1a;503.下一个更大元素II 文章讲解&#xff1a;代码随想录|503.下一个更大元素II 思路 和739. 每日温度 (opens new window)也几乎如出一辙&…

一周学会Django5 Python Web开发-Django5列表视图ListView

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计27条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

Matlab在同一张图中如何加入多个图例

根据代码最终画出的图片如下&#xff1a; 其实原理很简单&#xff0c;就是在一张figure中画多个坐标轴&#xff0c;每个坐标轴都有对应的图例&#xff0c;之后再将多余坐标轴隐藏&#xff0c;只保留一个即可。 代码如下&#xff1a; clear all; close all;dd_linewidth 1;a …

CSP-201712-1-最小差值

CSP-201712-1-最小差值 #include<iostream> #include<vector> #include<algorithm> using namespace std; vector<int>arr; int main() {int n, minDelta 99999;cin >> n;for (int i 0; i < n; i){int t;cin >> t;arr.push_back(t…

科技企业如何做到FTP数据安全保护

在数字化浪潮的推动下&#xff0c;科技企业的数据已成为推动创新、提升效率、增强竞争力的核心资源。数据的重要性不言而喻&#xff0c;它不仅包含了客户信息、市场分析、产品设计等关键信息&#xff0c;更是企业宝贵的资产。然而&#xff0c;随着数据量的激增&#xff0c;数据…

数据守护者:揭秘文件备份的重要性与实用策略

一、守护数据安全&#xff1a;文件备份的不可或缺性 在数字化时代&#xff0c;我们的工作、学习和生活都围绕着数据展开。无论是珍贵的家庭照片、重要的工作文件&#xff0c;还是个人的创意作品&#xff0c;这些数字资产都承载着我们的回忆、努力和创意。然而&#xff0c;随着…