Java进阶——静态代理与动态代理

news2025/4/2 0:15:43

        代理模式是一种常用的设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理模式就像是一个中间人,客户端通过代理来间接访问目标对象,可以在不修改目标对象的基础上,对目标对象的功能进行增强或扩展。代理模式主要分为静态代理和动态代理,本文将详细探讨这两种代理模式。

本文目录

    • 一、静态代理
      • 1. 代码实现
      • 2. 优缺点
    • 二、动态代理
      • 1. JDK动态代理实现
      • 2. CGLIB动态代理

一、静态代理

静态代理是指在编译时就已经确定代理类和目标类的关系。代理类和目标类都需要实现相同的接口,代理类中持有目标类的引用,在代理类的方法中调用目标类的相应方法,并可以在调用前后添加额外的逻辑。

1. 代码实现

// 定义接口
interface UserService {
    void addUser();
    void deleteUser();
}

// 实现类
class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

// 静态代理类
class UserServiceProxy implements UserService {
    private UserService target;

    public UserServiceProxy(UserService target) {
        this.target = target;
    }

    @Override
    public void addUser() {
        System.out.println("添加用户前的日志记录");
        target.addUser();
        System.out.println("添加用户后的日志记录");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户前的日志记录");
        target.deleteUser();
        System.out.println("删除用户后的日志记录");
    }
}


public class StaticProxy {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        UserService proxy = new UserServiceProxy(target);
        proxy.addUser();
        System.out.println("-------------------");
        proxy.deleteUser();
    }
}

在代理类的方法中,调用目标对象的方法前后添加了日志记录的逻辑

2. 优缺点

  • 优点:实现简单,易于理解,在编译时就可以确定代理关系,性能相对较高。
  • 缺点:代理类和目标类必须实现相同的接口,当接口方法发生变化时,代理类和目标类都需要修改。而且如果需要代理多个不同的目标类,就需要为每个目标类创建一个对应的代理类,代码会变得冗余。



二、动态代理

动态代理是指在运行时动态生成代理类,而不需要在编译时就确定代理类的代码。Java提供了两种实现动态代理的方式:JDK 动态代理和 CGLIB 动态代理。

1. JDK动态代理实现

JDK 动态代理是基于接口的动态代理,它使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface UserService {
    void addUser();
    void deleteUser();
}

class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

// 自定义InvocationHandler
class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(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(method.getName() + " 方法调用后的日志记录");
        return result;
    }
}


public class JdkDynamicProxy {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(target);
        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler
        );
        proxy.addUser();
        System.out.println("-------------------");
        proxy.deleteUser();
    }
}

这种方式不需要为每个目标类创建代理类,只需要实现 InvocationHandler 接口,就可以为多个目标类提供代理服务。只能代理实现了接口的类,不能代理没有实现接口的类。

2. CGLIB动态代理

CGLIB 动态代理是基于继承的动态代理,可以代理没有实现接口的类。CGLIB是一个强大的、高性能的代码生成库,通过继承目标类来生成代理类。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 目标类
class UserService {
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
    }
}

// 自定义MethodInterceptor
class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println(method.getName() + " 方法调用前的日志记录");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println(method.getName() + " 方法调用后的日志记录");
        return result;
    }
}


public class CglibDynamicProxy {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new MyMethodInterceptor());
        UserService proxy = (UserService) enhancer.create();
        proxy.addUser();
        System.out.println("-------------------");
        proxy.deleteUser();
    }
}

可以代理没有实现接口的类,灵活性更高,但是由于是基于继承实现的,所以不能代理 final 类和 final 方法。



← 上一篇 Java进阶——常用类及常用方法详解
记得点赞、关注、收藏哦!
下一篇 Java进阶——数组超详细整理 →

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

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

相关文章

非手性分子发光有妙招:借液晶之力,实现高不对称圆偏振发光

*本文只做阅读笔记分享* 一、圆偏振发光研究背景与挑战 圆偏振发光(CPL)材料在3D显示、光电器件等领域大有用处,衡量它的一个重要指标是不对称发光因子(glum)。早期CPL材料的glum值低,限制了实际应用。为…

YOLOv8+ Deepsort+Pyqt5车速检测系统

该系统通过YOLOv8进行高效的目标检测与分割,结合DeepSORT算法完成目标的实时跟踪,并利用GPU加速技术提升处理速度。系统支持模块化设计,可导入其他权重文件以适应不同场景需求,同时提供自定义配置选项,如显示标签和保存…

【干货】前端实现文件保存总结

⚠️⚠️文前推荐一下👉 前端必备工具推荐网站(图床、API和ChatAI、智能AI简历、AI思维导图神器等实用工具): 站点入口:http://luckycola.com.cn/ 前端实现文件保存实现总结 在Web开发中,文件下载是常见的交互需求。本文将系统总结前端实现文…

并发编程之FutureTask.get()阻塞陷阱:深度解析线程池CPU飚高问题排查与解决方案

FutureTask.get方法阻塞陷阱:深度解析线程池CPU飚高问题排查与解决方法 FutureTask.get()方法阻塞陷阱:深度解析线程池CPU飚高问题排查与解决方法1、情景复现1.1 线程池工作原理1.2 业务场景模拟1.3 运行结果1.4 发现问题:线程池没有被关闭1.…

在Ubuntu中固定USB设备的串口号

获取设备信息 lsusb # 记录设备的Vendor ID和Product ID(例如:ID 0403:6001)# 获取详细属性(替换X和Y为实际设备号) udevadm info -a /dev/ttyUSBX 结果一般如下 创建udev规则文件 sudo gedit /etc/udev/rules.d/us…

javaSE————文件IO(2)、

文件内容的读写——数据流 我们对于文件操作使用流对象Stream来操作,什么是流对象呢,水流是什么样的,想象一下,水流的流量是多种的,可以流100ml,也可以流1ml,流对象就和水流很像,我…

前端常问的宏观“大”问题详解(二)

JS与TS选型 一、为什么选择 TypeScript 而不是 JavaScript? 1. 静态类型系统:核心优势 TypeScript 的静态类型检查能在 编译阶段 捕获类型错误(如变量类型不匹配、未定义属性等),显著减少运行时错误风险。例如&…

智慧电力:点亮未来能源世界的钥匙

在科技日新月异的今天,电力行业正经历着前所未有的变革。智慧电力,作为这一变革的核心驱动力,正逐步改变着我们对电力的认知和使用方式。它不仅是电力行业的一次技术革新,更是推动社会可持续发展、实现能源高效利用的重要途径。 智…

架构师面试(二十三):负载均衡

问题 今天我们聊微服务相关的话题。 大中型微服务系统中,【负载均衡】是一个非常核心的组件;在微服务系统的不同位置对【负载均衡】进行了实现,下面说法正确的有哪几项? A. LVS 的负载均衡一般通过前置 F5 或是通过 VIP keepa…

NSSCTF(MISC)—[justCTF 2020]pdf

相应的做题地址:https://www.nssctf.cn/problem/920 binwalk分离 解压文件2AE59A.zip mutool 得到一张图片 B5F31内容 B5FFD内容 转换成图片 justCTF{BytesAreNotRealWakeUpSheeple}

坚持“大客户战略”,昂瑞微深耕全球射频市场

北京昂瑞微电子技术股份有限公司(简称“昂瑞微”)是一家聚焦射频与模拟芯片设计的高新技术企业。随着5G时代的全面到来,智能手机、智能汽车等终端设备对射频前端器件在通信频率、多频段支持、信道带宽及载波聚合等方面提出了更高需求&#xf…

LiteDB 数据库优缺点分析与C#代码示例

LiteDB 是一个轻量级的 .NET NoSQL 嵌入式数据库,完全用 C# 开发,支持跨平台(Windows、Linux、MacOS),并提供类似于 MongoDB 的简单 API。它以单文件形式存储数据,类似于 SQLite,支持事务和 ACID 特性,确保数据的一致性和可靠性。 优缺点分析 优点: 轻量级与嵌入式:…

Linux系统中快速安装docker

1 查看是否安装docker 要检查Ubuntu是否安装了Docker,可以使用以下几种方法: 方法1:使用 docker --version 命令 docker --version如果Docker已安装,输出会显示Docker的版本信息,例如: Docker version …

CP15 协处理器

ARMv7-A 一共支持 16 个协处理器,编号从 CP0~CP15。这里仅对CP15进行描述。 1、ARMv7-A 协处理器 ARMv7-A 处理器除了标准的 R0~R15,CPSR,SPSR 以外,由于引入了 MMU、TLB、Cache 等内容,ARMv7-A 使用协处理器来对这些…

网络运维学习笔记(DeepSeek优化版)026 OSPF vlink(Virtual Link,虚链路)配置详解

文章目录 OSPF vlink(Virtual Link,虚链路)配置详解1. 虚链路核心特性2. 基础配置命令3. 状态验证命令3.1 查看虚链路状态3.2 验证LSDB更新 4. 关键技术要点4.1 路径选择机制4.2 虚链路的链路优化 5. 环路风险案例 OSPF vlink(Virtual Link&a…

【区块链安全 | 第十六篇】类型之值类型(三)

文章目录 函数类型声明语法转换成员合约更新时的值稳定性示例 函数类型 函数类型是函数的类型。函数类型的变量可以通过函数进行赋值,函数类型的参数可以用来传递函数并返回函数。 函数类型有两种类型:内部函数和外部函数。 内部函数只能在当前合约内调…

Kubernetes对象基础操作

基础操作 文章目录 基础操作一、创建Kubernetes对象1.使用指令式命令创建Deployment2.使用指令式对象配置创建Deployment3.使用声明式对象配置创建Deployment 二、操作对象的标签1.为对象添加标签2.修改对象的标签3.删除对象标签4.操作具有指定标签的对象 三、操作名称空间四、…

Java与代码审计-Java基础语法

Java基础语法 package com.woniuxy.basic;public class HelloWorld {//入口函数public static void main(String[] args){System.out.println("Hello World");for(int i0;i< args.length;i){System.out.println(args[i]);}} }运行结果如下: 但是下面那个没有参数…

Xenium | 细胞邻域(Cellular Neighborhood)分析(fixed radius)

上节我们介绍了空间转录组数据分析中常见的细胞邻域分析&#xff0c;CN计算过程中定义是否为细胞邻居的方法有两种&#xff0c;一种是上节我们使用固定K最近邻方法(fixed k-nearest neighbors)定义细胞Neighborhood&#xff0c;今天我们介绍另外一种固定半径范围内(fixed radiu…

Python:爬虫概念与分类

网络请求&#xff1a; https://www.baidu.com url——统一资源定位符 请求过程&#xff1a; 客户端&#xff0c;指web浏览器向服务器发送请求 请求&#xff1a;请求网址(request url)&#xff1b;请求方法(request methods)&#xff1b;请求头(request header)&…