当前位置: 首页 > news >正文

Java基础:代理

这里写目录标题

    • 什么是代理
      • 1.静态代理(委托类、代理类):
        • 使用步骤:
        • 示例
        • 优缺点
      • 2.动态代理(委托类、中介类)
        • 2.1 JDK动态代理
          • 使用:
          • 中介类:
          • 示例1:
          • 示例2:
        • 2.2 CGLib动态代理
          • 使用方法:
          • 目标类(原始类)不能为final
          • 示例1:
          • 示例2:

什么是代理

代理模式是一种设计模式,简单说即是在不改变源码的情况下,实现对目标对象的功能扩展。


比如有个歌手对象叫Singer,这个对象有一个唱歌方法叫sing()

1 public class Singer{
2     public void sing(){
3         System.out.println("唱一首歌");
4     }  
5 }

假如你希望对目标对象Singer的sing方法进行功能扩展,例如在唱歌前后向观众问好和答谢,类似这样:

1 public void sing(){
2     System.out.println("向观众问好");
3     System.out.println("唱一首歌");
4     System.out.println("谢谢大家");
5 }  

但是又不能直接对源代码进行修改,甚至有可能你都不知道要对哪个目标对象进行扩展。这时就需要用到java的代理模式了。

1.静态代理(委托类、代理类):

静态代理要求原始类有实现某个接口。
需要创建一个代理类,实现和原始类相同的接口,并在需要增强的方法里,调用原始类的该方法,调用前后加上我们需要添加的代码。
使用的时候,直接创建一个代理类实例,调用目标方法即可。

使用步骤:

共同接口

public interface Action {public void doSomething();
}

原始类

public class RealObject implements Action{public void doSomething() {System.out.println("do something");}
}

代理类

public class Proxy implements Action {private Action realObject; public Proxy(Action realObject) {this.realObject = realObject;}public void doSomething() {System.out.println("proxy do");realObject.doSomething();}
}

使用

Proxy proxy = new Proxy(new RealObject());
proxy.doSomething();

示例

public interface ISinger {void sing();
}/***  目标对象实现了某一接口*/
public class Singer implements ISinger{public void sing(){System.out.println("唱一首歌");}  
}/***  代理对象和目标对象实现相同的接口*/
public class SingerProxy implements ISinger{// 接收目标对象,以便调用sing方法private ISinger target;public UserDaoProxy(ISinger target){this.target=target;}// 对目标对象的sing方法进行功能扩展public void sing() {System.out.println("向观众问好");target.sing();System.out.println("谢谢大家");}
}

测试类:

/*** 测试类*/
public class Test {public static void main(String[] args) {//目标对象ISinger target = new Singer();//代理对象ISinger proxy = new SingerProxy(target);//执行的是代理的方法proxy.sing();}
}

总结:这里做的事情无非就是,创建一个代理类SingerProxy,继承原始类的ISinger接口,实现其中的方法,并在实现中调用目标对象的方法。这里的关键是“调用目标对象方法”,如果直接重写就不叫代理了。

优缺点

优点:扩展原功能,不侵入原代码。

缺点:
①冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
②不易维护。代理对象必须提前写出,一旦接口发生了变化,代理对象的代码也要进行维护。

2.动态代理(委托类、中介类)

代理类在程序运行时运用反射机制创建的代理方式被成为动态代理。
也就是说,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。
相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

2.1 JDK动态代理

同样要求原始类实现某个接口,但不用手动创建代理类,而是创建中介类。中介类实现InvocationHandler接口。

使用:

调用Proxy类中的newProxyInstance(ClassLoader loader,Class<?>[]
interfaces,InvocationHandler h)方法以创建一个动态代理对象,其中第三个参数为我们创建的实现InvocationHandler接口的类(中介类),前两个参数可通过目标类.getclass().getxxx获取。

中介类:

需实现InvocationHandler接口,包含一个Object类型的对象,并利用其编写中介类的有参构造函数。重写的方法:public Object invoke(Object proxy, Method method, Object[] args) throws Throwable里,proxy表示代理类对象, method标识了我们具体调用的代理类的方法,args为这个方法的参数。

示例1:
public interface ISinger {void sing();
}/***  目标对象实现了某一接口*/
public class Singer implements ISinger{public void sing(){System.out.println("唱一首歌");}  
}-------------------------public class Test{public static void main(String[] args) {Singer target = new Singer();//这行要自己写ISinger proxy  = (ISinger) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("向观众问好");//目标对象方法前后编写需要扩展的代码Object returnValue = method.invoke(target, args);System.out.println("谢谢大家");return returnValue;}});proxy.sing();}
}
示例2:

public static void main(String[] args) throws InterruptedException {EnHello enHello=new EnHello();Hello hello=(Hello)Proxy.newProxyInstance(enHello.getClass().getClassLoader(),enHello.getClass().getInterfaces(), new MyInvocationHandler(enHello));hello.sayHello("Tom");}interface Hello{String sayHello(String username);
}static class EnHello implements Hello{@Overridepublic String sayHello(String username) {System.out.println("Hello, "+username);return "finished";}
}static class MyInvocationHandler implements InvocationHandler{private Object object;public MyInvocationHandler(Object object){this.object=object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result=null;System.out.println("before say hello");if("sayHello".equals(method.getName())){result=method.invoke(object,args);}System.out.println("before say hello");return result;}
}

还可以只为指定方法动态代理,在invoke方法加上以下判断:

String methodName = method.getName();
if("eating".equals(methodName))method.invoke(obj,args);

优点一:可以隐藏委托类的实现;
优点二:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理

2.2 CGLib动态代理

JDK动态代理和cglib动态代理有什么区别?

使用JDK动态代理的对象必须实现一个或多个接口
使用cglib代理的对象则无需实现接口。

cglib可以对任意类生成代理对象,它的原理是对目标对象进行继承代理,所以如果目标对象被final修饰,那么该类无法被cglib代理。

使用方法:

导包-创建MethodInterceptor实现类

使用cglib需要引入cglib的jar包,如果你已经有spring-core的jar包,则无需引入,因为spring中包含了cglib。

目标类(原始类)不能为final

目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

示例1:
/*** 目标对象,没有实现任何接口*/
public class Singer{public void sing() {System.out.println("唱一首歌");}
}----------------------/*** Cglib子类代理工厂*/
public class ProxyFactory implements MethodInterceptor{// 维护目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}// 给目标对象创建一个代理对象public Object getProxyInstance(){//1.工具类Enhancer en = new Enhancer();//2.设置父类en.setSuperclass(target.getClass());//3.设置回调函数en.setCallback(this);//4.创建子类(代理对象)return en.create();}/*
使用时只有intercept方法中,代码行 method.invoke前后的代码需要修改,其他的代码直接使用
*/@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("向观众问好");//执行目标对象的方法Object returnValue = method.invoke(target, args);System.out.println("谢谢大家");return returnValue;}
}-----------------------/*** 测试类*/
public class Test{public static void main(String[] args){//目标对象Singer target = new Singer();//代理对象Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance();//执行代理对象的方法proxy.sing();}
}
示例2:
public class TestCglib implements MethodInterceptor {    Object target;   //动态生成一个新的类,使用父类的无参构造方法创建一个指定了特定回调的代理实例    public Object getProxyObject(Object object) {      this.target = object;       //增强器,动态代码生成器     Enhancer enhancer=new Enhancer();        //回调方法enhancer.setCallback(this); //设置生成类的父类类型        enhancer.setSuperclass(target.getClass());   //动态生成字节码并返回代理对象      return enhancer.create();   }public Object intercept(Object o, Method method, Object[] objects, MethodProxy 
methodProxy) throws Throwable {System.out.println("----------before");    // 调用方法      Object result = methodProxy.invoke(target, objects);   System.out.println("----------after");       return null;  }
}//使用
public static void main(String[] args) {Boss boss=(Boss) new TestCglib().getProxyObject(new Boss());boss.eating();boss.sleeping();
}

相关文章:

Java基础:代理

这里写目录标题 什么是代理1.静态代理&#xff08;委托类、代理类&#xff09;&#xff1a;使用步骤&#xff1a;示例优缺点 2.动态代理&#xff08;委托类、中介类&#xff09;2.1 JDK动态代理使用&#xff1a;中介类&#xff1a;示例1&#xff1a;示例2&#xff1a; 2.2 CGLi…...

每日一学——防火墙2

防火墙是一种网络安全设备&#xff0c;用于保护计算机网络免受未经授权的访问、攻击和恶意行为的影响。以下是一些防火墙的基本概念&#xff1a; 防火墙规则&#xff1a;防火墙会根据预先设置的规则来决定允许或拒绝特定的网络流量。这些规则可以指定源 IP 地址、目标 IP 地址、…...

Web学习笔记-React(组合Components)

笔记内容转载自 AcWing 的 Web 应用课讲义&#xff0c;课程链接&#xff1a;AcWing Web 应用课。 CONTENTS 1. 创建父组件2. 从上往下传递数据3. 传递子节点4. 从下往上调用函数5. 兄弟组件间传递消息6. 无状态函数组件7. 组件的生命周期 本节内容是组件与组件之间的组合&#…...

【strstr函数的介绍和模拟实现——超详细版】

strstr函数的介绍和模拟实现 strstr函数的介绍 资源来源于cplusplus网站 strstr函数声明&#xff1a; char *strstr( const char *str1, const char *str2 ); 它的作用其实就是&#xff1a; 在字符串str1中查找是否含有字符串str2&#xff0c;如果存在&#xff0c;返回str2在…...

【Terraform】Terraform自动创建云服务器脚本

Terraform 是由 HashiCorp 创建的开源“基础架构即代码”工具 &#xff08;IaC&#xff09; 使用HCL&#xff08;配置语言&#xff09;描述云平台基础设施&#xff08;这里教你使用低级基础设施&#xff1a;交换机、云服务器、VPC、带宽&#xff09; Terraform提供者&#xf…...

TCP机制之确认应答及超时重传

TCP因为其可靠传输的特性被广泛使用,这篇博客将详细介绍一下TCP协议是如何保证它的可靠性的呢?这得主要依赖于其确认应答及超时重传机制,同时三次握手四次挥手也起到了少部分不作用,但是主要还是由确认应答和超时重传来决定的;注意:这里的可靠传输并不是说100%能把数据发送给接…...

Openharmony3.2 源码编译(ubuntu 22.04) 过程记录

OS: ubuntu 22.04 x64 1. 下载源码 1.1 安装码云repo工具 sudo apt install python3-pip git-lfsmkdir ~/bin curl https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 -o ~/bin/repo chmod ax ~/bin/repo pip3 install -i https://repo.huaweicloud.com/repository/p…...

PostgreSQL 数据库使用 psql 导入 SQL

最近我们有一个 SQL 需要导入到 PostgreSQL &#xff0c;但数据格式使用的是用&#xff1a; -- -- TOC entry 7877 (class 0 OID 21961) -- Dependencies: 904 -- Data for Name: upload_references; Type: TABLE DATA; Schema: public; Owner: - --COPY public.upload_refere…...

容器编排学习(三)端口映射与Harber镜像仓库介绍

一 对外发布服务&#xff08;端口映射&#xff09; 1 概述 新创建容器的IP 地址是随机的 容器在重启后每次 IP 都会发生变化 容器服务只有宿主机才能访问 如何才能使用容器对外提供稳定的服务? 容器端口可以与宿主机的端口进行映射绑定 从而把宿主机变成对应的服务&a…...

Day_13 > 指针进阶(2)

目录 1.函数指针数组 2.指向函数指针数组的指针 3.回调函数 qsort()函数 代码示例 void* 4.结束 今天我们在进阶指针的基础上&#xff0c;学习进阶指针的第二部分 1.函数指针数组 首先我们回顾一下指针数组 char* arr[5]://字符指针数组 - 数组 - 存放的是字符指针 in…...

对Transformer中的Attention(注意力机制)的一点点探索

摘要&#xff1a;本文试图对 Transformer 中的 Attention 机制进行一点点探索。并就 6 个问题深入展开。 ✅ NLP 研 1 选手的学习笔记 简介&#xff1a;小王&#xff0c;NPU&#xff0c;2023级&#xff0c;计算机技术 研究方向&#xff1a;文本生成、摘要生成 文章目录 一、为啥…...

车内信息安全技术-安全技术栈-软件安全

操作系统 1.隔离技术 信息安全中的隔离技术通常指的是将不同安全级别的信息或数据隔离开来,以保护敏感信息不受未授权的访问或泄露。在操作系统中,常见的隔离技术包括:虚拟化技术:通过虚拟化软件,将物理计算机分割成多个独立的虚拟计算机,每个虚拟计算机都可以运行独立的…...

Redis常见命令

命令可以查看的文档 http://doc.redisfans.com/ https://redis.io/commands/ 官方文档&#xff08;英文&#xff09; http://www.redis.cn/commands.html 中文 https://redis.com.cn/commands.html 个人推荐这个 https://try.redis.io/ redis命令在线测试工具 https://githubfa…...

Android Studio实现一笔画完小游戏

文章目录 一、项目概述二、开发环境三、详细设计3.1、数据库设计3.2、普通模式3.3、随机模式3.4、关卡列表 四、运行演示五、项目总结六、源码获取 一、项目概述 Android一笔画完是一种益智游戏&#xff0c;玩家需要从起点开始通过一条连续的线&#xff0c;将图形中所有的方块…...

【Python 程序设计】数据人员入门【02/8】

一、说明 介绍如何管理 Python 依赖项和一些虚拟环境最佳实践。 以下文章是有关 Python 数据工程系列文章的一部分&#xff0c;旨在帮助数据工程师、数据科学家、数据分析师、机器学习工程师或其他刚接触 Python 的人掌握基础知识。迄今为止&#xff0c;本初学者指南包括&#…...

学习笔记——树上哈希

普通子树哈希 树上的很多东西都是转化成链上问题的&#xff0c;比如树上哈希 树上哈希&#xff0c;主要是用于树的同构这个东西上的 什么是树的同构&#xff1f; 如图&#xff0c;不考虑节点编号&#xff0c;三棵树是同构的 将树转化成链&#xff0c;一般有两种方式&#xf…...

Opencv快速入门教程,Python计算机视觉基础

快速入门 OpenCV 是 Intel 开源计算机视觉库。它由一系列 C 函数和少量 C 类构成&#xff0c; 实现了图像处理和计算机视觉方面的很多通用算法。 OpenCV 拥有包括 300 多个 C 函数的跨平台的中、高层 API。它不依赖于其它的外部库——尽管也 可以使用某些外部库。 OpenCV 对非…...

laravel 报错误信息 Carbon\Exceptions\InvalidFormatException

Carbon\Exceptions\InvalidFormatException Unexpected data found. at vendor\nesbot\carbon\src\Carbon\Traits\Creator.php:687 683▕ return $instance; 684▕ } 685▕ 686▕ if (static::isStrictModeEnabled()) { ➜ 687…...

UI自动化之混合框架

什么是混合框架&#xff0c;混合框架就是将数据驱动与关键字驱动结合在一起&#xff0c;主要用来回归业务主流程&#xff0c;将核心流程串联起来。 上一篇我们写到了关键字驱动框架&#xff0c;关键字驱动框架是针对一个业务场景的单条测试用例的。 我们以163邮箱的登录到创建…...

SQL创建用户-非DM8.2环境(达梦数据库)

DM8:达梦数据库SQL创建用户-非DM8.2环境 环境介绍 环境介绍 在没有图形化界面&#xff0c;或者想快速创建用户&#xff0c;可以使用一下SQL语句&#xff1b;将其中的 CESHI 替换为要创建的用户名即可&#xff0c;默认创建了数据表空间&#xff0c;索引表空间&#xff0c;文件大…...

Thread类中run和start的区别

答&#xff1a;调用线程类中的 start 方法&#xff0c;才开始创建并启动线程&#xff0c;而线程被回收&#xff0c;则是要执行完线程的入口方法&#xff08;对于主线程来说&#xff0c;则是要执行完 main 方法&#xff09;&#xff0c;这里要回收线程则是要将&#xff08;&…...

ElementUI浅尝辄止35:Checkbox 多选框

一组备选项中进行多选 1.如何使用&#xff1f; 单独使用可以表示两种状态之间的切换&#xff0c;写在标签中的内容为 checkbox 按钮后的介绍。 //在el-checkbox元素中定义v-model绑定变量&#xff0c;单一的checkbox中&#xff0c;默认绑定变量的值会是Boolean&#xff0c;选…...

讲讲如何用IDEA开发java项目——本文来自AI创作助手

使用IDEA开发Java项目&#xff0c;您可以按照以下步骤进行操作&#xff1a; 下载并安装IntelliJ IDEA 您可以从JetBrains官网下载并安装最新版的IntelliJ IDEA。 创建项目 启动IDEA&#xff0c;在欢迎界面中选择“Create New Project”或者在主菜单中选择“File”->“Ne…...

Kafka3.0.0版本——消费者(Range分区分配策略以及再平衡)

目录 一、Range分区分配策略原理1.1、Range分区分配策略原理的示例一1.2、Range分区分配策略原理的示例二1.3、Range分区分配策略原理的示例注意事项 二、Range 分区分配策略代码案例2.1、创建带有4个分区的fiveTopic主题2.2、创建三个消费者 组成 消费者组2.3、创建生产者2.4、…...

WeiTools

目录 1.1 WeiTools 1.2 getTime 1.3 getImageView 1.4 StringEncode 1.4.1 // TODO Auto-generated catch block WeiTools package com.shrimp.xiaoweirobot.tools;...

目标检测数据集:医学图像检测数据集(自己标注)

1.专栏介绍 ✨✨✨✨✨✨目标检测数据集✨✨✨✨✨✨ 本专栏提供各种场景的数据集,主要聚焦:工业缺陷检测数据集、小目标数据集、遥感数据集、红外小目标数据集,该专栏的数据集会在多个专栏进行验证,在多个数据集进行验证mAP涨点明显,尤其是小目标、遮挡物精度提升明显的…...

【系统设计系列】数据库

系统设计系列初衷 System Design Primer&#xff1a; 英文文档 GitHub - donnemartin/system-design-primer: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards. 中文版&#xff1a; https://github.com/donnemarti…...

mp4压缩视频不改变画质?跟我这样压缩视频大小

在当今数字化时代&#xff0c;视频文件变得越来越普遍&#xff0c;然而&#xff0c;这些文件通常都很大&#xff0c;给存储和传输带来了困难&#xff0c;为了解决这个问题&#xff0c;许多人都希望将视频压缩得更小&#xff0c;而又不牺牲画质&#xff0c;下面就来看看具体应该…...

AQS同步队列和等待队列的同步机制

理解AQS必须要理解同步队列和等待队列之间的同步机制&#xff0c;简单来说流程是&#xff1a; 获取锁失败的线程进入同步队列&#xff0c;成功的占用锁&#xff0c;占锁线程调用await方法进入条件等待队列&#xff0c;其他占锁线程调用signal方法&#xff0c;条件等待队列线程进…...

vue3实现无限循环滚动的方法;el-table内容无限循环滚动的实现

需求&#xff1a;vue3实现一个div内的内容无限循环滚动 方法一&#xff1a; <template><div idcontainer><div class"item" v-foritem in 5>测试内容{{{ item }}</div></div> </template><script setup> //封装一个方法…...

简述设计web站点的一般步骤/鹤壁seo推广

[1].[代码] [Python]代码1.生成随机数02 import random #这个是注释&#xff0c;引入模块03 rnd random.randint(1,500)#生成1-500之间的随机数0405 2.读文件0607 f open("c:\\1.txt","r")08 lines f.readlines()#读取全部内容09 for line in lines10 p…...

小门户网站开发/宁波百度seo排名优化

下面是本篇的大纲&#xff1a; 1、AppWidget 框架类2、在 Android 如何使用 Widget3、AppWidget 框架的主要类介绍4、DEMO 讲解1、AppWidget 框架类 1、AppWidgetProvider &#xff1a;继承自 BroadcastRecevier &#xff0c; 在AppWidget 应用 update、enable、disable 和 del…...

常熟做网站公司排名/佛山百度关键词排名

下面是几个与oracle紧密相关的unix/linux内核参数&#xff0c;在安装数据库的时候&#xff0c;一般都需要根据实际情况进行调整。Init.ora Parameter Kernel Parameter db_block_buffers shmmax, shmall db_files(maxdatafiles) nfile, maxfiles large_pool_size shmmax…...

linux上安装wordpress/seo营销推广全程实例

代理设计模式&#xff1a; 动态代理举例&#xff1a; 接口&#xff1a; 被代理类&#xff1a; 测试&#xff1a;...

紧紧抓住推进党风廉政建设的"牛鼻子"中央纪委监察部网站/广告资源发布平台

QPS/TPS/并发量/系统吞吐量的概念 2017年08月13日 17:24:47 阅读数&#xff1a;10682 我们在日常工作中经常会听到QPS/TPS这些名词&#xff0c;也会经常被别人问起说你的系统吞吐量有多大。这个问题从业务上来讲&#xff0c;可以理解为应用系统每秒钟最大能接受的用户访问量。或…...

网站建设前的功能/b站推广链接

字节跳动启动了史上规模最大的招聘共计7000岗位&#xff0c;每个人有两次投递机会包括抖音&#xff0c;今日头条&#xff0c;西瓜在内评论区好热闹俗话说“三月不跳槽&#xff0c;四月徒伤悲”又到了一年一度的“跳槽黄金季”在职场中&#xff0c;有不少的的瞬间我们自己觉得洪…...