【Java基础】代理

news2024/9/24 17:40:44

文章目录

  • 代理
  • 代理模式的优点
  • 代理模式类型
    • 基于JDK的静态代理
    • 基于JDK的动态代理

代理

一种设计模式,不允许用户直接访问核心功能,而是通过代理来访问核心类的核心功能

举个例子,如果我们现在需要一个银行转账系统,我们需要在一个Java类中实现:

  • 转账方法(核心)
  • 验证用户身份、验证金额
  • 一些后续服务等

初学者很容易将这些方法都写在同一个Java类中,然而以上三个方法其实每一个都是一个很复杂的流程,写在一起会导致当前类的功能量太大,所以我们想到了一个办法:将这些方法分开写,不再写到同一个方法中,将最核心的业务,也就是转账业务,由支付宝或者微信代理完成,而其他的服务由微信或者支付宝自身完成,用户通过访问支付宝代理来完成最核心的转账业务。——也就是代理模式,用户只能访问代理,而不能访问核心功能
在这里插入图片描述

代理模式的优点

  1. 防止用户直接访问核心方法带来一些不必要的危机(代码冗余等)
  2. 能够对核心方法进行功能的增强

代理模式类型

代理模式分为三类:基于JDK的静态代理、基于JDK的动态代理、基于CGLB的动态代理,下面我们详细说一下每一种代理模式:
在这里插入图片描述

基于JDK的静态代理

静态代理中,我们需要实现核心类与核心对象,代理类与代理对象,以及一个定义核心类中核心方法的接口,代理类与核心类中都需要对接口中核心方法的实现,并在代理类中创建核心对象,进行代理,在用户访问时,通过创建代理对象来访问核心对象,来完成我们的代理流程
在这里插入图片描述我们依然以上面的银行转账系统为例子,我们先定义一个Pay接口,其中定义我们的转账方法(核心方法),但不实现

public interface Pay {
    // 定义核心方法
    public void pay(String A, String B, Double money);
}

再定义Bank核心类,继承Pay接口并实现接口中的核心方法Pay()

public class Bank implements Pay {
    @Override
    public void pay(String A, String B, Double money) {
        System.out.println(A + "给" +B+ "转账了" +money+ "元");
    }
}

定义代理类,我们假定为支付宝AliPay,让代理类也继承接口并实现其中的核心方法,其中也包括对核心方法功能的增强,如验证功能以及后续服务功能:

public class AliPay implements Pay {

    // 1. 定义一个好被代理的类--->核心类
    private Bank bank = new Bank();

    public void check(String A, String B,Double money){
        System.out.println("对A进行了验证");
        System.out.println("对B进行了验证");
        System.out.println("对金额进行了验证");
    }

    private void service(){
        System.out.println("转账完成后进行的事后服务");
    }

    @Override
    public void pay(String A, String B, Double money) { // 核心方法的实现
        check(A,B,money);
        bank.pay(A,B,money);
        service();
    }
}

最后我们创建Test测试类,来测试我们以上的代理流程:

public class Test {
    public static void main(String[] args) {
        AliPay aliPay = new AliPay();
        aliPay.pay("zhangsan", "lisi", 100.12);
    }
}

我们可以看到,在用户界面,也就是Test类中,用户只能通过访问代理,也就是创建aliPay对象来对Bank核心类中的核心方法Pay()进行访问,而不是直接对核心类中的核心方法进行访问,这样就完成了代理,下面是内存图:
在这里插入图片描述

基于JDK的动态代理

先考虑一个问题,如果我们的代理需要同时代理很多个核心类的话,那么会出现什么情况?比如一个商店,对服装工厂、鞋子工厂、裤子工厂等等多个工厂同时进行代理,那么在这个代理类的代理对象中,我们就需要创建很多个核心对象,来完成我们的代理流程,并且每多代理一个工厂就要手动增加一个核心对象,这也是静态代理的一个缺陷:同一个代理类代理多个目标类是很难实现的

在这里插入图片描述

那么我们就需要用动态代理模式来完成这个功能。与静态代理不同的是,在动态代理中,每一个核心对象会由一个独立的代理对象进行代理,而不是全部都由同一个代理对象代理,也就是一对一模式,如下图

在这里插入图片描述

那我们如何实现这个一对一模式呢?

我们商店的例子中,商店作为动态代理,其中包含一个Object对象,以及一个将核心对象传入代理对象的构造器:

public class Shop {
    private Object object; 
    public Shop(Object o){ // 传入目标类的目标对象(代理类的代理对象)
        object = o;
    }
}

public class Test {
    public static void main(String[] args) {
        ClothesFactory clothesFactory = new ClothesFactory(); 
        Shop shop = new Shop(clothesFactory);
    }
}

这样在用户访问时,每创建一个代理对象shop,就会将一个核心对象的地址传给代理对象,进行代理,也就是完成了上面说的一对一模式

在这里插入图片描述

静态代理中,我们一一实现了每一个核心类的核心方法,继承了相对应的接口,动态代理中同样需要实现方法,但是并不像静态代理那样分别进行继承和实现,这里我们定义一个返回值为Object类型的方法getInstance()通过这个方法我们可以获取到核心类的类对象,从而完成对其中方法的实现

public Object getProxyInstance(){ // object.getClass() 获取目标类的类对象
    							  // object.getClass().getInterfaces() 获取目标类所继承的接口,告知代理类所代理的核心功能是什么
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
    } // 这里的返回值是一个对象

之后我们需要对核心类中的核心方法进行调用,在上一步我们已经知道了核心类的类对象信息,那么我们就可以通过反射来调用其中的方法,这里我们需要继承一个接口InvocationHandler,来对其中的invoke()方法进行重写,来调用核心类中的核心方法(暂时不做深究,和反射中的invoke()方法是一个方法)

public class Shop implements InvocationHandler { 
    //三个参数的讲解
    //1.Object:jdk创建的代理类,无需赋值
    //2.Method:目标类当中的方法,jdk提供,无需赋值
    //3.Object[]:目标类当中的方法的参数,jdk提供,无需赋值
	@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        method.invoke(object,args);
        service();
        return null;
    }
}

那么我们在Test类中获取到相对应的类信息用什么来接收呢?答案是需要用相关接口进行接收。观察整个流程,没有任何一个地方可以调用到其中的核心方法,如果我们直接创建子类ClothesFactory对象对其中的核心方法进行调用的,这种方式并没有通过任何代理,如下:

public class Test {
    public static void main(String[] args) {
        ClothesFactory clothesFactory = new ClothesFactory(); // 这里利用反射创建对象也可以
		clothesFactory.BuyClothes("XL");// 这种方式并没有走任何代理,只是直接调用了ClothesFactory中的BuyClothes()方法
    }
}

在这里插入图片描述

所以只能通过接口进行调用,这里是一个多态,接口Clothes为父类,创建父类引用,让他指向子类对象,然后在调用方法时,因为子类ClothesFactory对方法进行了重写,那么只能访问重写方法,这样就完成了整个代理流程,访问到了我们的核心方法

在这里插入图片描述

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

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

相关文章

git创建本地分支并track跟踪远程分支

git创建本地分支并track跟踪远程分支 查看本地分支与远程分支的映射关系: git branch -vv 查看远程都有什么分支: git branch -r 在本地自动新建一个xxx分支,且自动track跟踪远程的同名xxx分支: git checkout --track origin/xx…

MinIO Packet Pushers 播客: 汤姆-里昂,《NFS 必死》。

我们真的很喜欢 Packet Pushers 的团队。他们的播客是业内最好的播客之一,涵盖了从堆栈顶部到底部的技术。我们最近有机会赞助传奇人物 Tom Lyon 对 Ethan Banks 和 Drew Conry-Murray 的采访。Packet Pushers 的团队对 Tom 最近题为“NFS(网络文件系统&…

数据结构(13)——平衡二叉树(红黑树)

欢迎来到博主的专栏——数据结构 博主ID:代码小号 文章目录 红黑树红黑树节点之间的关系红黑树的插入uncle节点为红色uncle节点是黑色或者没有uncle节点 红黑树 平衡二叉树最出名的除了AVL树之外就是红黑树(RBTree),所谓红黑树&a…

JSON 格式详解

JSON 格式详解 随着互联网的发展和各种 Web 应用程序的普及,数据交换已经成为了我们日常开发中的重要环节。而在各种数据交换格式中,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,以其简洁、易于阅…

2024.9.4(k8s)

一、前期准备 1、配置主机映射 [rootk8s-master ~]# vim /etc/hosts 192.168.8.168 k8s-master 192.168.8.176 k8s-node1 192.168.8.177 k8s-node2[rootk8s-master ~]# ping k8s-master 2、配置yum源 [rootk8s-master yum.repos.d]# vim kubernetes.repo [kubernetes] n…

智能医学(二)——MDPI特刊推荐

特刊征稿 01 特刊名称: eHealth and mHealth: Challenges and Prospects, 2nd Volume 参与期刊: 截止时间: 摘要提交截止日期 关闭(2024年6月30日) 投稿截止日期 2024年9月30日 目标及范围: 关键字 l 人工智能 l 计算机…

模拟实现string类及体验传统深拷贝

目录 strcpy 构造函数 优化 拷贝构造/深拷贝 operator size/operator[] operator<< c_str() 模拟string::iterator 插入 push_back() append() operator reserve npos strcpy strcpy是将/0拷贝完成后才会停止。 构造函数 string():_str(nullptr) {} st…

vite 打包 学习

plugins.jsimport vue from "vitejs/plugin-vue"; // 自动引入插件 import autoImport from "unplugin-auto-import/vite"; import setupExtend from "unplugin-vue-setup-extend-plus/vite"; import { ElementPlusResolver } from unplugin-vue…

国内Etsy开店注册账号需要什么?

Etsy作为海外知名二手电商平台&#xff0c;对于原创手工产品的商家来说具有巨大的市场流量与商机&#xff0c;但注册Etsy账号对于国内跨境电商用户来说确实存在一定的难度&#xff0c;作为Etsy也是小有名气的小商家&#xff0c;今天也分享一下开店的经验帮助大家出海。 一、Ets…

终端安全一体化解决方案有哪些?值得收藏的五款终端安全系统

随着信息技术的迅猛发展&#xff0c;企业和个人面临着越来越多的安全威胁。终端作为连接互联网和用户的第一线&#xff0c;其安全性直接影响到整个网络乃至组织的安全态势。为了应对日益复杂的网络环境&#xff0c;许多企业开始采用终端安全一体化解决方案&#xff0c;以期达到…

EVPN学习

三、VXLAN BGP EVPN基本原理_vxlan的type2,type3区别-CSDN博客 华为数通笔记VXLAN&BGP EVPN_vxlan为什么用bgp协议-CSDN博客

【MeterSphere】vnc连接不上selenium-chrome容器

目录 一、现象 二、查看配置文件 docker-compose-seleniarm.yml 三、处理 3.1 删除上图当中的三行 3.2 msctl reload 3.3 重新连接 前言:使用vnc连不上ms的selenium-chrome容器,看不到里面运行情况,以前其实可以,后来不行了,研究了一下 一、现象 输入IP:端口,连…

vmware 17.6 pro for personal USE初体验

新学期开学了&#xff0c;暑假期间把台式机放在办公室远程&#xff0c;无赖期间经常断电&#xff0c;把我的老台给烧坏了&#xff0c;检测了下固态硬盘和机械硬盘&#xff0c;好歹能用。但是win11的系统奔溃了。就花了半天时间重装。*v* 悲剧的是&#xff0c;一些软件环境必须…

怎么合并pdf文件?6个PDF文件合并成一个,只需要这5步!

在日常工作和学习中&#xff0c;我们经常需要处理多个PDF文件&#xff0c;有时为了方便查阅和管理&#xff0c;需要将它们合并成一个文件。以下是几种实用的方法来合并PDF文件&#xff0c;特别是如何将6个PDF文件合并成一个。 PDF合并工具推荐1. 金舟PDF编辑器 第一步、从金舟…

php民宿短租平台Java民宿预约系统python民宿预订住宿与可视化分析系统(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

【C++ 第十八章】C++11 新增语法(4)

前情回顾&#xff1a; 【C11 新增语法&#xff08;1&#xff09;&#xff1a;1~6 点】 C11出现与历史、花括号统一初始化、initializer_list初始化列表、 auto、decltype、nullptr、STL的一些新变化 【C11 新增语法&#xff08;2&#xff09;&#xff1a;7~8 点】 右值引用和…

爬虫练习(js逆向解密)

目标 网站地址交易列表 - 福建省公共资源交易电子公共服务平台 (fj.gov.cn) 抓取内容如下&#xff1a; 分析 查找js代码 点击下一页翻页的时候&#xff0c;查看请求返回的数据&#xff0c;发现data数据是经过加密后得到的 通过全局搜索data,发现有两千多个结果&#xff0c;一个…

Qt将数据库中的数据导出为html

一、源码分享 bool ReportFormUtils::exportReportHtml(QString &errString, const QString tableName, const QString savePathAndName, const QString tableTitle, const QString tableInfo) {Q_UNUSED(errString)Q_UNUSED(tableName)Q_UNUSED(savePathAndName)#define …

原子放大1亿倍能看到另一个宇宙?微观与宏观是一体的?

原子的行星模型 开始阐述前,先从物质 组成与体积 方面进行一些铺垫与解释:我们身处于物质的世界,大部分物质由分子构成,分子由原子构成,原子由电子、质子、中子构成,质子,中子又是由夸克构成。鉴于人类目前的科技,或许未来也可以知道电子的组成是否有更加微观的存在…

kubernetes中的资源管理

目录 1 资源管理介绍 2 资源管理的方式 2.1 kubectl命令介绍及格式 2.2 资源类型 2.3 kubectl 常见操作指令 2.3.1 CREATE 示例&#xff1a; 2.3.1.1 指定资源类型创建 2.3.1.2 查看创建的资源类型 2.3.1.3 查看pods是否正确被创建并且被调度 2.3.1.4 查看名为shuyan 的 Dep…