Java中的代理机制

news2025/5/11 12:15:56

目录

什么叫代理

静态代理

优缺点

优点:

缺点:

动态代理

JDK动态代理

核心类

JDK动态代理的实现

步骤

示例

特点

CGLIB动态代理

代理机制对比

总结


什么叫代理

代理模式是一种比较好理解的设计模式。简单来说就是我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。

Java支持两种代理机制:

  1. 静态代理(手动编写代理类)
  2. 动态代理(运行时动态生成代理类)

静态代理

静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(需要对每个目标类都单独写一个代理类)。实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。

上面我们是从实现和应用角度来说的静态代理,从 JVM 层面来说, 静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。

静态代理实现步骤:

  1. 定义一个接口及其实现类;
  2. 创建一个代理类同样实现这个接口
  3. 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情
//首先,我们要写出联系代理类与目标类的桥梁,接口
public interface BuyClothes {
    public void clothes(String size);
}
//然后我们写出目标类,这里用ClothedFactory为例
public class ClothesFactory implements BuyClothes{
    @Override
    public void clothes(String size) {
        System.out.println("已经为您定制好了大小为" + size +"的衣服");
    }
}
//写出静态代理类
public class StaticProxy implements BuyClothes {
    private ClothesFactory clothesFactory = new ClothesFactory();
 
    //重写核心方法
    @Override
    public void clothes(String size) {
        //代理类与目标类建立起了桥梁
        clothesFactory.clothes(size);
    }
}
//模拟用户方面
public class Test {
    public static void main(String[] args) {
        StaticProxy staticProxy = new StaticProxy();
        //此处,用户访问目标类的路径:用户-->代理类StaticProxy---(以共同接口BuyClothes为中间节点)--->目标类ClothesFactory-->完成clothes()方法
        staticProxy.clothes("XXXL");
    }
}

优缺点

优点:

  • 简单直观
  • 适合代理少量方法

缺点:

  • 每个目标类需手动编写代理类
  • 代码冗余

动态代理

一个代理类代理多个目标类

  • 在静态代理中,我们代理的仅仅是一个方法,但是在平时,一个类通常会有很多方法,对应的对象也会调用多个类,那么此时如果还是用静态代理,就会特别麻烦,所以就有了动态代理

  • JDK中提供了一个方法,可以动态的实现新增的接口,该方法是

    Proxy.newProxyInstance() 

动态代理在运行时动态生成代理类,无需手动编写。Java提供两种实现方式:

  1. JDK动态代理(基于接口)
  2. CGLIB动态代理(基于类继承)

JDK动态代理

核心类

java.lang.reflect.Proxy;    //生成代理类

java.lang.reflect.InvocationHandler;    //定义代理逻辑

JDK动态代理的实现

步骤
  • 创建接口,定义目标类要完成的功能
  • 创建目标类实现接口
  • 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
    • ​​​​调用目标方法
    • 增强功能
  • 使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型
示例
import java.lang.reflect.*;

// 1. 定义接口和目标类(同上)

// 2. 实现 InvocationHandler
class LogHandler implements InvocationHandler {
    private Object target;  // 目标对象

    public LogHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("【动态代理】调用方法: " + method.getName());
        Object result = method.invoke(target, args);  // 调用目标方法
        System.out.println("【动态代理】方法执行完毕");
        return result;
    }
}

// 3. 生成代理对象
public class JdkProxyDemo {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new LogHandler(target)
        );
        proxy.save();  // 通过代理调用
    }
}
特点
  • 要求:目标类必须实现接口
  • 性能:反射调用稍慢,但现代JVM已优化

CGLIB动态代理

  • cglib是第三方的工具库, 创建代理对象
  • cglib的原理是继承, cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法, 实现功能的修改
  • 因为cglib是继承,重写方法,所以要求目标类不能是final的, 方法也不能是final的
  • 不需要目标类有接口,通过继承就可以
  • 经常用于框架中,例如Spring(SpringAOP)  

代理机制对比

特性静态代理JDk动态代理CGLIB动态代理
是否需要接口
生成方式手动编写运行时动态生成运行时动态生成
性能中等(反射调用)高(字节码增强)
使用场景简单、少量代理基于接口的代理无接口的类代理

总结

  • 静态代理:简单但冗余,适合少量固定增强
  • JDK动态代理:灵活,虚接口,适合SpringAOP等场景
  • CGLIB:更高效,可代理无接口类,但需注意final限制

根据需求选择合适代理方式

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

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

相关文章

Jenkins linux安装

jenkins启动 service jenkins start 重启 service jenkins restart 停止 service jenkins stop jenkins安装 命令切换到自己的下载目录 直接用命令下载 wget http://pkg.jenkins-ci.org/redhat-stable/jenkins-2.190.3-1.1.noarch.rpm 下载直接安装 rpm -ivh jenkins-2.190.3-…

Webug4.0靶场通关笔记-靶场搭建方法(3种方法)

目录 一、虚拟机绿色版本 1. 开启phpstudy 2. 访问靶场 二、Docker版本 1.拉取镜像 2.启动镜像 三、源码安装版本 1. 搭建环境 (1)安装PHPStudy (2)WeBug4.0靶场源码 (3)安装Navicat &#xff…

【Web】LACTF 2025 wp

目录 arclbroth lucky-flag whack-a-mole arclbroth 看到username为admin能拿到flag 但不能重复注册存在的用户 这题是secure-sqlite这个库的问题,底层用的是C,没处理好\0字符截断的问题 (在 Node.js 中,由于其字符串表示方式…

【日撸 Java 三百行】综合任务 1

目录 Day 10:综合任务 1 一、题目分析 1. 数据结构 2. 相关函数基本知识 二、模块介绍 1. 初始化与成绩矩阵的构建 2. 创建总成绩数组 3. 寻找成绩极值 三、代码与测试 小结 拓展:关于求极值的相关算法 Day 10:综合任务 1 Task&…

华为私有协议Hybrid

实验top图 理论环节 1. 基本概念 Hybrid接口: 支持同时处理多个VLAN流量,且能针对不同VLAN配置是否携带标签(Tagged/Untagged)。 核心特性: 灵活控制数据帧的标签处理方式,适用于复杂网络场景。 2. 工作…

数据库实验10

设计性实验 1.实验要求 1.编写函数FsumXXX,1~n(参数)求和; GO CREATE FUNCTION Fsum065 (n INT) RETURNS INT AS BEGIN DECLARE sum INT 0 WHILE n > 0 BEGIN SET sum sum n SET n n - 1 END RETURN sum END …

jflash下载时出现 Could not read unit serial number! 的解决方法

出现的原因是由于Jlink原厂固件SN码是-1 我用的版本是v6.40 解决方法:添加序列号 1.打开:J-Link commander 之后在命令栏输入:exec setsnxxxxxxxx 2.添加序列号到license,打开J-Link License Manager V6.40 jlink-v640下载软件…

Linux 信号终篇(总结)

前文:本文是对信号从产生到被处理的过程中的概念和原理的总结,如果想了解具体实现,请查看前两篇博客:Linux 信号-CSDN博客、Linux 信号(下篇)-CSDN博客 一、信号的产生 1.1 信号产生的五种条件 ①键盘组…

LVGL对象(Objects)

文章目录 🧱 一、LVGL 中的对象(lv\_obj)🔹 lv\_obj\_t 的作用 🧩 二、对象的分类结构(类比继承)🧰 三、对象的创建与销毁✅ 创建对象示例:创建一个按钮❌ 删除对象 &…

服务器配置错误导致SSL/TLS出现安全漏洞,如何进行排查?

SSL/TLS 安全漏洞排查与修复指南 一、常见配置错误类型‌ 弱加密算法与密钥问题‌ 使用弱密码套件&#xff08;如DES、RC4&#xff09;或密钥长度不足&#xff08;如RSA密钥长度<2048位&#xff09;&#xff0c;导致加密强度不足。 密钥管理不当&#xff08;如私钥未加密存…

路由重发布

路由重发布 实验目标&#xff1a; 掌握路由重发布的配置方法和技巧&#xff1b; 掌握通过路由重发布方式实现网络的连通性&#xff1b; 熟悉route-pt路由器的使用方法&#xff1b; 实验背景&#xff1a;假设学校的某个分区需要配置简单的rip协议路由信息&#xff0c;而主校…

C++修炼:stack和queue

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

【计算机视觉】优化MVSNet可微分代价体以提高深度估计精度的关键技术

优化MVSNet可微分代价体以提高深度估计精度的关键技术 1. 代价体基础理论与分析1.1 标准代价体构建1.2 关键问题诊断 2. 特征表示优化2.1 多尺度特征融合2.2 注意力增强匹配 3. 代价体构建优化3.1 自适应深度假设采样3.2 可微分聚合操作改进 4. 正则化与优化策略4.1 多尺度代价…

软考错题集

一个有向图具有拓扑排序序列&#xff0c;则该图的邻接矩阵必定为&#xff08;&#xff09;矩阵。 A.三角 B.一般 C.对称 D.稀疏矩阵的下三角或上三角部分包含非零元素&#xff0c;而其余部分为零。一般矩阵这个术语太过宽泛&#xff0c;不具体指向任何特定性 质的矩阵。对称矩阵…

T2I-R1:通过语义级与图像 token 级协同链式思维强化图像生成

文章目录 速览摘要1 引言2 相关工作统一生成与理解的 LMM(Unified Generation and Understanding LMM.)用于大型推理模型的强化学习(Reinforcement Learning for Large Reasoning Models.)3 方法3.1 预备知识3.2 语义级与令牌级 CoT语义级 CoT(Semantic-level CoT)令牌级…

Dockers部署oscarfonts/geoserver镜像的Geoserver

Dockers部署oscarfonts/geoserver镜像的Geoserver 说实话&#xff0c;最后发现要选择合适的Geoserver镜像才是关键&#xff0c;所以所以所以…&#x1f437; 推荐oscarfonts/geoserver的镜像&#xff01; 一开始用kartoza/geoserver镜像一直提示内存不足&#xff0c;不过还好…

扩增子分析|微生物生态网络稳定性评估之鲁棒性(Robustness)和易损性(Vulnerability)在R中实现

一、引言 周集中老师团队于2021年在Nature climate change发表的文章&#xff0c;阐述了网络稳定性评估的原理算法&#xff0c;并提供了完整的代码。自此对微生物生态网络的评估具有更全面的指标&#xff0c;自此网络稳定性的评估广受大家欢迎。本系列将介绍网络稳定性之鲁棒性…

【含文档+PPT+源码】基于微信小程序的社区便民防诈宣传系统设计与实现

项目介绍 本课程演示的是一款基于微信小程序的社区便民防诈宣传系统设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套…

【MySQL】存储引擎 - ARCHIVE、BLACKHOLE、MERGE详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…

代码随想录第41天:图论2(岛屿系列)

一、岛屿数量&#xff08;Kamacoder 99&#xff09; 深度优先搜索&#xff1a; # 定义四个方向&#xff1a;右、下、左、上&#xff0c;用于 DFS 中四向遍历 direction [[0, 1], [1, 0], [0, -1], [-1, 0]]def dfs(grid, visited, x, y):"""对一块陆地进行深度…