由反射引出的Java动态代理与静态代理

写在开头

在《深入剖析Java中的反射,由浅入深,层层剥离!》这篇文章中我们讲反射时,曾提到过Java的动态代理中使用了反射技术,那么好,今天我们要就着反射的索引,来学习一下Java中的代理!

代理模式

在Java中有多达23种的设计模式(后面Java基础更新完后,会找个时间详细的去写写这些设计模式),恰当的设计模式的使用能够提升代码的效率,简化代码的复杂性。

而今天我们要说的代理模式就是其中之一,所谓代理是为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

大白话:买房的(客户方),房产销售(代理方),卖房的(委托方)
在这里插入图片描述
在Java中有静态代理和动态代理两种实现方式,继续放下看!!!

静态代理

所谓静态代理,一般是针对编译期就已经完成了接口,实现类,代理类的定义,我们对目标对象的增强需要手工去完成,一个目标对象就要有个代理类,非常不灵活。

静态代理的实现步骤

1,因为代理类与被目标对象有相似的行为(共同),所以我们先创建一个接口。

public interface SaleHouse {String saleHouse();
}

2,提供接口的实现类,当做目标对象

public class SaleHouseImpl implements SaleHouse{@Overridepublic String saleHouse() {return "我要卖房子啦!!!";}
}

3,代理类同样也要实现接口,并在目标方法前后做一些控制操作

public class SaleHouseProxy implements SaleHouse{private SaleHouse saleHouse;//提供一个包含目标对象的有参构造public SaleHouseProxy(SaleHouse saleHouse) {this.saleHouse = saleHouse;}@Overridepublic String saleHouse() {//调用方法前,我们可以加一些自己的控制System.out.println("我要收代理费!!!");System.out.println("--------------------");String s = saleHouse.saleHouse();System.out.println(s);System.out.println("--------------------");//调用方法后,我们依旧可以操作System.out.println("我要拿提成!!!");return "这就是静态代理";}
}

4,客户端调用代理类,并传入目标对象

public class Test {public static void main(String[] args) throws FileNotFoundException {//客户端调用静态代理SaleHouse saleHouse = new SaleHouseImpl();SaleHouseProxy saleHouseProxy = new SaleHouseProxy(saleHouse);saleHouseProxy.saleHouse();}
}

5,控制台查看打印结果

我要收代理费!!!
--------------------
我要卖房子啦!!!
--------------------
我要拿提成!!!

动态代理

其实无论是静态代理还是静态代理,在我们的日常开发中,使用的都是很多,但对于SpringAop、RPC等框架来说,动态代理发挥着相当大的作用,动态代理具有:运行时控制,灵活性更好的特点。
那怎么实现动态代理呢?
如下三种方式:

JDK 动态代理
CGLib 动态代理
使用 Spring aop 模块完成动态代理功能 //今天先不说这个

JDK动态代理

实现步骤:
1,定义一个接口及其实现类;
代码同静态代理中步骤1,步骤2;

2,自定义 InvocationHandler (调用处理器)并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;

public class JdkDynamicInvocationHandler implements InvocationHandler {//代理类中的真实对象private final Object target;public JdkDynamicInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//调用方法前,我们可以加一些自己的控制System.out.println("我要收代理费!!!");Object invoke = method.invoke(target, args);//调用方法后,我们依旧可以操作System.out.println("我要拿提成!!!");return invoke;}
}

3,通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;其实,这一步也可以写在第2步的代码里,不过为了代码的可读性,我们进行解耦实现!
3.1,定义一个工厂类,在工厂类中通过Proxy.newProxyInstance()方法获取某个类的代理对象

public class JdkDynamicProxyFactory {public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(), // 目标类的类加载器target.getClass().getInterfaces(),  // 代理需要实现的接口,可指定多个new JdkDynamicInvocationHandler(target)   // 代理对象对应的自定义 InvocationHandler);}

3.2,客户端传入目标对象,实现代理扩展

  //客户端调用静态代理
SaleHouse proxySaleHouse = (SaleHouse) JdkDynamicProxyFactory.getProxy(new SaleHouseImpl());
proxySaleHouse.saleHouse();

4,控制台输出

我要收代理费!!!
我要卖房子啦!!!
我要拿提成!!!

【扩展】
关于Proxy类的静态工厂方法newProxyInstance()如何创建代理实例的过程,感兴趣的可以去读源码,或者参考下面这篇文章《代理模式在开源代码中的应用》

CGLIB 动态代理

其实在JDK动态代理中有一个弊端,那就是只能代理接口或接口的实现类,那么未实现任何接口的类就不能代理了吗?答案是否定的,因为咱们有CGLIB!

CGLIB (Code Generation Library) 是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成,CGLIB 通过继承方式实现代理。

实现步骤:
1,引入cglib依赖
因为是第三方实现的动态代理,所以在使用前先引入依赖包

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

2,定义一个类;

public class Person {public void eat(){System.out.println("我在吃饭!!!");}
}

3,自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;

public class CglibMethodInterceptor implements MethodInterceptor {/*** @param o           被代理的对象(需要增强的对象)* @param method      被拦截的方法(需要增强的方法)* @param args        方法入参* @param methodProxy 用于调用原始方法*/@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//调用方法前,我们可以加一些自己的控制System.out.println("饭前先洗手");Object object = methodProxy.invokeSuper(o, args);//调用方法前,我们可以加一些自己的控制System.out.println("饭后要擦嘴");return object;}
}

4,创建一个工厂类,用来构建代理对象,通过 Enhancer 类的 create()方法实现;

public class CglibProxyFactory {public static Object getProxy(Class<?> clazz) {// 创建动态代理增强类Enhancer enhancer = new Enhancer();// 设置类加载器enhancer.setClassLoader(clazz.getClassLoader());// 设置被代理类enhancer.setSuperclass(clazz);// 设置方法拦截器enhancer.setCallback(new CglibMethodInterceptor());// 创建代理类return enhancer.create();}
}

5、客户端调用,通过反射传入Person类信息

public static void main(String[] args) throws FileNotFoundException {//客户端调用静态代理Person person = (Person) CglibProxyFactory.getProxy(Person.class);person.eat();}

6、输出

饭前先洗手
我在吃饭!!!
饭后要擦嘴

OK,终于码完了动态代理,自己还去看了很久的源码,头昏脑涨!

结尾彩蛋

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

在这里插入图片描述

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

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

相关文章

2024年美赛数学建模A题思路分析 - 资源可用性和性别比例

# 1 赛题 问题A&#xff1a;资源可用性和性别比例 虽然一些动物物种存在于通常的雄性或雌性性别之外&#xff0c;但大多数物种实质上是雄性或雌性。虽然许多物种在出生时的性别比例为1&#xff1a;1&#xff0c;但其他物种的性别比例并不均匀。这被称为适应性性别比例的变化。…

Map和Set讲解

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f4d5;格言&#xff1a;那些在暗处执拗生长的花&#xff0c;终有一日会馥郁传香欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 集合框架 模型 Set 常见方法和说明 Set总结 Map说明 Map常见方法和说明 Map 中HashMap的 …

Git 指令

Git 安装 操作 命令行 简介&#xff1a; Git 是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或大的项目。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 Git 与常用的版本控制工具 CVS, Subversion …

网络协议与攻击模拟_14DNS欺骗

DNS欺骗就是利用某种方式将我们访问的域名解析到其他服务器上&#xff0c;从而使得我们无法正常访问到原本我们想要访问的网站。 一、DNS欺骗过程 首先在windows server 2016虚拟机上搭建网站服务&#xff0c;kali作为攻击机从而实现中间人攻击&#xff0c;使用ettercap工具的…

python中的可变与不可变、深拷贝和浅拷贝

个人猜想&#xff08;很遗憾失败了&#xff09; 在硬盘或者系统中存在一个字符集 如果存在硬盘中&#xff0c;那么硬盘出厂的时候他的字符集所占用的空间就已经确定了。 如果存在于系统的话&#xff0c;硬盘应该在出厂的时候为系统设置一个存储系统字符集的地方。在安装系统…

SimpleDateFormat 格式化 Date 时间戳

前言 Date 是 Java 中经常用来表示时间的类型&#xff0c;但将 Date 类型的数据发送给前端时&#xff0c;通常会呈现出乱码的状态&#xff0c;用户不宜理解&#xff0c;所以要通过 SimpleDateFormat 把 Date 类型的数据格式化为用户容易理解的格式 如下是 Date 的格式&#xff…

【2024美赛E题】985博士解题思路分析(持续更新中)!

【2024美赛E题】985博士解题思路分析&#xff01; 加群可以享受定制等更多服务&#xff0c;或者搜索B站&#xff1a;数模洛凌寺 联络组织企鹅&#xff1a;936670395 以下是E题老师的解题思路&#xff08;企鹅内还会随时更新文档&#xff09;&#xff1a; 2024美赛E题思路详解…

北朝隋唐文物展亮相广西,文物预防性保护网关保驾护航

一、霸府名都——太原博物馆收藏北朝隋朝文物展 2月1日&#xff0c;广西民族博物馆与太原博物馆携手&#xff0c;盛大开启“霸府名都——太原博物馆北朝隋文物展”。此次新春展览精选了北朝隋唐时期150多件晋阳文物珍品。依据“巍巍雄镇”“惊世古冢”“锦绣名都”三个单元&am…

车载语音交互赛道研究:大模型揭幕2.0时代 商业模式重塑

大模型正给车载语音交互赛道带来颠覆性变革。 根据高工智能汽车研究院调研获取的信息&#xff0c;核心原因为&#xff1a;1.0时代&#xff0c;车载语音交互玩家可使用自身的小模型&#xff1b;2.0时代&#xff0c;很可能需基于通用大模型&#xff08;训练成本极为高昂&#xf…

【2024年美国大学生数学建模竞赛】F题非法的野生动物贸易 完整数据

小云更新了全网最全的F题数据 另外也为大家分享&#xff1a; 技术文档&#xff0c;包括问题分析、建立模型、求解结果等&#xff0c;配套有思路分析视频、代码讲解视频。美赛官方限制总页数为25页&#xff0c;我们的思路长度为35页以上。所有模型都有求解代码和指标&#xff0…

ManageEngine推出云原生身份平台以解决劳动力IAM挑战

ManageEngine推出云原生身份平台以解决企业员工身份与访问管理&#xff08;IAM&#xff09;面临的挑战。该公司还为其本地身份治理和管理&#xff08;IGA&#xff09;解决方案添加了先进的安全功能。 IAM 内置通用目录可在企业应用程序之间集中管理用户身份&#xff0c;使用身…

嵌入式系统设计师之存储管理

目录 一、Flat存储管理方式&#xff08;I&#xff09; 二、分区存储管理&#xff08;II&#xff09; 1、固定分区 2、可变分区 3、内存保护 三、地址重定位 (II) 1、逻辑地址 2、物理地址 四、页式存储管理 &#xff08;II&#xff09; 五、虚拟存储管理&#xff08;II&#x…