Java设计模式——代理模式

news2025/1/20 4:37:27

静态代理:

Java静态代理是设计模式中的一种,它通过创建一个代理类来代替原始类,从而提供额外的功能或控制原始类的访问。

如何使用Java静态代理

要创建一个静态代理,你需要有一个接口,一个实现该接口的目标类,以及一个代理类,该代理类也实现了该接口。代理类持有一个对目标对象的引用,并在其方法调用中调用目标对象的相应方法。

// 定义一个接口
interface Calculator {
    int add(int a, int b);
}

// 目标类
class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
}

// 代理类
class CalculatorProxy implements Calculator {
    private Calculator calculator;

    public CalculatorProxy(Calculator calculator) {
        this.calculator = calculator;
    }

    @Override
    public int add(int a, int b) {
        System.out.println("Before calculation");
        int result = calculator.add(a, b);
        System.out.println("After calculation");
        return result;
    }
}

// 测试类
public class ProxyExample {
    public static void main(String[] args) {
        Calculator target = new CalculatorImpl();
        Calculator proxy = new CalculatorProxy(target);

        int result = proxy.add(5, 3);
        System.out.println("Result: " + result);
    }
}

在这个例子中,Calculator是一个接口,CalculatorImpl是目标类,CalculatorProxy是代理类。当我们调用代理类的add方法时,它会首先打印"Before calculation",然后调用目标对象的add方法,最后打印"After calculation"。 

为什么使用静态代理

  • 解耦:可以在不修改目标对象的情况下,通过代理对象添加额外的功能或控制访问。

  • 保持干净:代理类可以为目标对象提供一个干净的接口,隐藏了目标对象的实现细节。

  • 权限控制:可以在代理类中添加额外的权限检查,以控制对目标对象的访问。

缺点

  • 代码冗余:每次添加一个新的功能都需要创建一个新的代理类。

  • 静态:因为代理类是静态的,所以不能在运行时改变它们的行为。

总的来说,静态代理是一种简单且直接的方式来实现代理模式,它在很多情况下都是非常有用的,特别是当你需要对目标对象进行额外控制或添加额外功能时

动态代理:

 Java动态代理是Java语言提供的一个强大的特性,它允许你在运行时创建代理类和代理实例。这使得你可以在运行时为一个接口创建一个代理实例,而不需要手动编写实现该接口的类。动态代理通常在需要添加额外逻辑(例如日志记录、事务管理等)到现有代码中而不修改现有代码的情况下使用。

  • 是在内存中生成代理对象的一种技术
  • 无需手写代理类,也不会存在代码编译的过程。运用在内存中生产代理类的技术在JVM的运行区造一个代理对象,只需对需要修改的部分进行编辑。

编写流程:

  1. 准备一个目标类对象
  2. 使用jdk的API动态的生成代理对象
  3. 调用代理对象执行相应的方法

 

如何使用Java动态代理

要使用Java动态代理,你需要先创建一个接口,然后实现一个InvocationHandler接口,最后使用Proxy.newProxyInstance()方法创建代理实例

1.ClassLoader loader:

固定写法,指定目标类对象的类的加载器即可,用于加载目标类及其接口的字节码文件,通常使用目标类的字节码文件调用getClassLoader()方法可得到。

2.Class<?>[] interfaces:

固定写法,指定目标类的所以接口的字节码对象的数组,通常使用目标类的字节码文件调用getinterfaces()方法可得到。

3.InvocationHander h:

这个参数是一个接口,主要关注它里面的一个方法,它会在代理类调用方法时执行,也就是说,在代理类对象中调用的任何方法都会执行invoke()方法。所以在此方法中进行代码的扩展。

invoke()方法中参数的含义:

  1. proxy:就是代理类对象的一个引用也就是Proxy.newProxyInstance()方法的返回值;此引用几乎不会用到。
  2.  method:对应的就是触发invoke执行的方法的Method对象。假如我们调用了Xxx方法,该方法触发了invoke执行,那么method就是Xxx方法对应的反射对象Method。
  3.   args:代理对象调用方法时传入的实际参数

 

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

public interface Hello {
    void sayHello();
}

public class HelloImpl implements Hello {
    @Override
    public void sayHello() {
        System.out.println("Hello World!");
    }
}

public class DynamicProxyExample {
    public static void main(String[] args) {
        Hello hello = new HelloImpl();
        Hello proxy = (Hello) Proxy.newProxyInstance(
                hello.getClass().getClassLoader(),
                hello.getClass().getInterfaces(),
                new MyInvocationHandler(hello)
        );

        proxy.sayHello();
    }
}

public 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("Before method execution.");
        Object result = method.invoke(target, args);
        System.out.println("After method execution.");
        return result;
    }
}

在上面的例子中,我们首先定义了一个Hello接口和一个实现该接口的HelloImpl类。然后,我们创建了一个MyInvocationHandler类,实现了InvocationHandler接口,该类在方法调用前后打印日志。最后,在DynamicProxyExample类中,我们使用Proxy.newProxyInstance()方法创建了一个代理实例,并传入了一个MyInvocationHandler实例

 

为什么使用动态代理

  • 解耦:你可以将通用逻辑(如日志记录、事务管理等)与特定的业务逻辑分开。

  • 代码复用:可以为多个对象提供相同的额外功能,而无需在每个类中重复相同的代码。

  • 运行时改变行为:你可以在运行时改变对象的行为,而无需修改源代码。

注意事项

  • 接口代理:动态代理只能为接口创建代理,不能为类创建代理。

  • 性能开销:动态代理可能会带来一些性能开销,因为它涉及反射调用。

总的来说,Java动态代理是一个非常强大的特性,可以在很多场景中帮助你更加灵活地管理和组织你的

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

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

相关文章

Python pyglet制作彩色圆圈“连连看”游戏

原文链接&#xff1a; Python 一步一步教你用pyglet制作“彩色方块连连看”游戏(续)-CSDN博客文章浏览阅读1.6k次&#xff0c;点赞75次&#xff0c;收藏55次。上期讲到相同的色块连接&#xff0c;链接见&#xff1a; Python 一步一步教你用pyglet制作“彩色方块连连看”游戏-…

Java中的容器

Java中的容器主要包括以下几类&#xff1a; Collection接口及其子接口/实现类&#xff1a; List 接口及其实现类&#xff1a; ArrayList&#xff1a;基于动态数组实现的列表&#xff0c;支持随机访问&#xff0c;插入和删除元素可能导致大量元素移动。LinkedList&#xff1a;基…

【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题

文章目录 一、什么是时间复杂度和空间复杂度&#xff1f;1.1 算法效率1.2 时间复杂度的概念1.3 空间复杂度的概念1.4 复杂度计算在算法中的意义 二、时间复杂度的计算2.1 大O渐进表示法2.2 常见时间复杂度计算举例 三、空间复杂度的计算四、Leetcode刷题1. 消失的数2. 旋转数组…

对接实例:致远OA对接金蝶云星空场景解决方案

正文&#xff1a;很多企业在数字化建设得时候&#xff0c;对内部系统间的高效协同与数据流转提出了更高要求。金蝶云星空作为行业领先的ERP解决方案&#xff0c;与专业协同办公平台致远OA的深度对接&#xff0c;在人员管理、组织架构、采购与销售合同、费用审批等在内的全方位企…

javaWeb项目-网上图书商城系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、Java技术 Java语…

Flask框架初探-如何在本机发布一个web服务并通过requests访问自己发布的服务-简易入门版

Flask框架初探 在接触到网络框架之前我其实一直对一个事情有疑惑&#xff0c;跨语言的API在需要传参的情况下究竟应该如何调用&#xff0c;之前做过的项目里&#xff0c;我用python做了一个代码使用一个算法得到一个结果之后我应该怎么给到做前端的同学或者同事&#xff0c;之前…

2024腾讯一道笔试题--大小写字母移动

题目&#x1f357; 有一个字符数组,其中只有大写字母和小写字母,将小写字母移到前面, 大写字符移到后面,保持小写字母本身的顺序不变,大写字母本身的顺序不变, 注意,不要分配新的数组.(如:wCelOlME,变为wellCOME). 思路分析&#x1f357; 类似于冒泡排序&#xff0c;两两比较…

JavaSE中的String类

1.定义方式 常见的三种字符串构造 public class Test1 {public static void main(String[] args) {// 使用常量串构造String str1 "abc";System.out.println(str1);// 直接newString对象String str2 new String("ABC");System.out.println(str2);// 使用…

ssm056基于Java语言校园快递代取系统的设计与实现+jsp

校园快递代取系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本校园快递代取系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短…

node基础 第二篇

01 ffmpeg开源跨平台多媒体处理工具&#xff0c;处理音视频&#xff0c;剪辑&#xff0c;合并&#xff0c;转码等 FFmpeg 的主要功能和特性:1.格式转换:FFmpeg 可以将一个媒体文件从一种格式转换为另一种格式&#xff0c;支持几乎所有常见的音频和视频格式&#xff0c;包括 MP…

工业控制(ICS)---OMRON

OMRON FINS 欧姆龙厂商 命令代码(Command CODE)特别多&#xff0c;主要关注读写相关&#xff0c;如&#xff1a; Memory Area Read (0x0101) Memory Area Write (0x0102) Multiple Memory Area Read (0x0104) Memory Area Transfer (0x0105) Parameter Area Read (0x0201) Pa…

ARM_day8:温湿度数据采集应用

1、IIC通信过程 主机发送起始信号、主机发送8位(7位从机地址1位传送方向(0W&#xff0c;1R))、从机应答、发数据、应答、数据传输完&#xff0c;主机发送停止信号 2、起始信号和终止信号 SCL时钟线&#xff0c;SDA数据线 SCL高电平&#xff0c;SDA由高到低——起始信号 SC…

Linux时间同步练习

题目如下&#xff1a; 一.配置server主机要求如下&#xff1a; 1.server主机的主机名称为 ntp_server.example.com 2.server主机的IP为&#xff1a; 172.25.254.100 3.server主机的时间为1984-11-11 11&#xff1a;11&#xff1a;11 4.配置server主机的时间同步服务要求可以被所…

突破数据存储瓶颈!转转业财系统亿级数据存储优化实践

1.背景 1.1 现状 目前转转业财系统接收了上游各个业务系统&#xff08;例如&#xff1a;订单、oms、支付、售后等系统&#xff09;的数据&#xff0c;并将其转换为财务数据&#xff0c;最终输出财务相关报表和指标数据&#xff0c;帮助公司有效地进行财务管理和决策。 转转业…

Matlab|基于改进遗传算法的配电网故障定位

目录 1 主要内容 2 部分代码 3 部分程序结果 4 下载链接 1 主要内容 该程序复现文章《基于改进遗传算法的配电网故障定位》&#xff0c;将改进的遗传算法应用于配电网故障定位中, 并引入分级处理思想, 利用配电网呈辐射状的特点, 首先把整个配电网划分为主干支路和若干独立…

Pr2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 Premiere简称“Pr”&#xff0c;是一款超强大的视频编辑软件&#xff0c;它可以提升您的创作能力和创作自由度&#xff0c;它是易学、高效、精确的视频剪辑软件&#xff0c;提供了采集、剪辑、调色、美化音频、字幕添加、输出、D…

minio如何配置防盗链

MinIO 是一个开源的对象存储服务器&#xff0c;用于存储大量的数据&#xff0c;同时提供了丰富的功能和 API。配置防盗链可以帮助你控制谁可以访问存储在 MinIO 上的对象。以下是在 MinIO 中配置防盗链的一般步骤&#xff1a; 编辑 config.json 文件&#xff1a; 找到 MinIO 服…

【Godot4自学手册】第三十七节钥匙控制开门

有些日子没有更新了&#xff0c;实在是琐事缠身啊&#xff0c;今天继续开始自学Godot4&#xff0c;继续完善地宫相关功能&#xff0c;在地宫中安装第二道门&#xff0c;只有主人公拿到钥匙才能开启这扇门&#xff0c;所以我们在合适位置放置一个宝箱&#xff0c;主人公开启宝箱…

vue+element作用域插槽

作用域插槽的样式由父组件决定&#xff0c;内容却由子组件控制。 在el-table使用作用域插槽 <el-table><el-table-column slot-scope" { row, column, $index }"></el-table-column> </el-table>在el-tree使用作用域插槽 <el-tree>…

【Java开发指南 | 第十一篇】Java运算符

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 算术运算符关系运算符位运算符逻辑运算符赋值运算符条件运算符&#xff08;?:&#xff09;instanceof 运算符Java运算符优先级 Java运算符包括&#xff1a;算术运算符、关系运算符、位运算符、逻辑运算符、赋值…