温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

0、前言

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。

1、静态代理

静态代理是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,需要为每一个被代理对象创建一个代理类。静态代理的实现比较简单,但是每个被代理对象都需要创建一个代理类,因此在代理对象比较多时,会导致代码几余和维护成本增加。

静态代理有两种实现,继承聚合两种模式。

1.1、继承模式

需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者继续相同父类,代理对象继承目标对象,重新目标对象的方法。

 目标对象:

package proxy.staticproxy.extends_model;

//目标对象
public class UserService {

    public void login(){
        System.out.println("login success");
    }
}

代理类:

package proxy.staticproxy.extends_model;

//代理对象
public class UserServiceProxy extends UserService{

    public void login(){
        System.out.println("开始执行--------------");
        super.login();
    }
}

 测试类:

package proxy.staticproxy;

import proxy.staticproxy.extends_model.UserServiceProxy;
import proxy.staticproxy.implements_model.FactoryOne;
import proxy.staticproxy.implements_model.FactoryOneProxy;
import proxy.staticproxy.implements_model.IFactory;

public class Test {

    @org.junit.Test
    public void extends_model(){
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.login();
    }

    //  待代理类来处理
    /// 场景:当不想改动被代理类的业务逻辑,在处理开始和结束分别加上时间显示
    /// 处理核心逻辑:需要实现被代理类的接口及方法,在实现方法中田间需要添加的业务处理逻辑
    @org.junit.Test
    public void implements_model(){
        // 创建被代理类的对象
        IFactory word = new FactoryOne();

        // 创建代理类的对象
        IFactory proxyPaperFactory = new FactoryOneProxy(word);
        proxyPaperFactory.production();
    }
    // 直接调用被代理类业务处理
    @org.junit.Test
    public void test01(){
        // 创建被代理类的对象
        IFactory word = new FactoryOne();
        word.production();
    }
}

 执行结果:

开始执行--------------
login success

1.2、聚合模式

Subject:抽象主题角色,抽象主题类可以是抽象类,也可以是接口,是一个最普通的业务类型定义,无特殊要求。
RealSubject:具体主题角色,也叫被委托角色、被代理角色。是业务逻辑的具体执行者。
Proxy:代理主题角色,也叫委托类、代理类。它把所有抽象主题类定义的方法给具体主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后工作。 

Subject 接口:

package proxy.staticproxy.implements_model;

public interface IFactory {

    void production();
}

 RealSubject 类:

package proxy.staticproxy.implements_model;

public class FactoryOne implements IFactory {

    @Override
    public void production() {
        System.out.println(" 被代理类,开始初始化 ");

        System.out.println(" 生产笔记本、鼠标、键盘等等 ");

        System.out.println(" 被代理类处理完成 ");
    }
}

Proxy 类:

package proxy.staticproxy.implements_model;

public class FactoryOneProxy implements IFactory {
    private IFactory factory; // 用被代理类对象进行实例化

    public FactoryOneProxy(IFactory factory) {
        this.factory = factory;
    }

    @Override
    public void production() {
        System.out.println(" 代理开始工作 ,在此可以添加处理逻辑");
        factory.production();
        System.out.println(" 代理结束工作 ,在此可以添加处理逻辑");
    }
}

 测试类:

package proxy.staticproxy;

import proxy.staticproxy.extends_model.UserServiceProxy;
import proxy.staticproxy.implements_model.FactoryOne;
import proxy.staticproxy.implements_model.FactoryOneProxy;
import proxy.staticproxy.implements_model.IFactory;

public class Test {

    @org.junit.Test
    public void extends_model(){
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.login();
    }

    //  待代理类来处理
    /// 场景:当不想改动被代理类的业务逻辑,在处理开始和结束分别加上时间显示
    /// 处理核心逻辑:需要实现被代理类的接口及方法,在实现方法中田间需要添加的业务处理逻辑
    @org.junit.Test
    public void implements_model(){
        // 创建被代理类的对象
        IFactory word = new FactoryOne();

        // 创建代理类的对象
        IFactory proxyPaperFactory = new FactoryOneProxy(word);
        proxyPaperFactory.production();
    }
    // 直接调用被代理类业务处理
    @org.junit.Test
    public void test01(){
        // 创建被代理类的对象
        IFactory word = new FactoryOne();
        word.production();
    }
}

运行结果:

 代理开始工作 ,在此可以添加处理逻辑
 被代理类,开始初始化 
 生产笔记本、鼠标、键盘等等 
 被代理类处理完成 
 代理结束工作 ,在此可以添加处理逻辑

2、动态代理

动态代理是一种代理模式的实现方式,它在运行期间根据需要动态生成代理对象,无需手动编写代理类,可以减少代码几余和维护成本。动态代理适用于需要代理的对象数量较多,代理类实现对灵活的场景,例Spring框架中的Spring AOP(面向切面编程)功能。

动态代理的实现方式也有两种,JDK动态代理CGLB动态代理两种模式。本文重点介绍JDK动态代理,

在JDK中,有一个Proxy类(名词,代理人)。Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态的生成实现类。Proxy类提供的有一个静态方法:newProxyInstance()方法给我们的目标对象(委托对象)返回一个代理对象。

核心方法:newProxyInstance方法的三个参数,按照顺序分别是 ClassLoader (类加载器),interfaces(一组接口,接口数组),InvocationHandler(调用处理器)。

ClassLoader (类加载器)

定义了由哪个classLoader对象来对生成的代理对象进行加载。

接口数组:

一个Interface对象的数组,表示将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了。

调用处理器:

一个InvocationHandler接口,表示代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程席。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法(传入InvocationHandler接口的子类)。

对象接口:

package proxy.dynamicproxy.v3;

public interface IAnimal {
    public void run();

    public void eat();

    public void sleep();
}

被代理类<Cat>:

package proxy.dynamicproxy.v3;

public class Cat implements IAnimal{

    @Override
    public void run() {
        System.out.println("Cat Run invoking!!!");
    }

    @Override
    public void eat() {
        System.out.println("Cat eat invoking!!!");
    }

    @Override
    public void sleep() {
        System.out.println("Cat sleep invoking!!!");
    }
}

被代理类<Dog>: 

package proxy.dynamicproxy.v3;

public class Dog implements IAnimal{

    @Override
    public void run() {
        System.out.println("Dog Run invoking!!!");
    }

    @Override
    public void eat() {
        System.out.println("Dog eat invoking!!!");
    }

    @Override
    public void sleep() {
        System.out.println("Dog sleep invoking!!!");
    }
}

 代理类工具类:

package proxy.dynamicproxy.v3;

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

public class ProxyUtils {

    public Object object;

    public ProxyUtils(Object object) {
        this.object = object;
    }

    public Object createProxyObj(){

        // 动态代理 顾名思义 针对接口动态生成代理类处理业务逻辑
        // 返回动态代理
        /*
        ClassLoader loader, 要实现接口的类加载器
        Class<?>[] interfaces,接口类
        InvocationHandler h 处理类
        * **/
        ClassLoader loader = object.getClass().getClassLoader();
//        Class<?>[] interfaces = new Class[]{argObj.getClass()};  // 当是接口
        Class<?>[] interfaces = object.getClass().getInterfaces(); // 当是类直接获取对应的接口方法;

        InvocationHandler handler = new IFactoryInvocationHandler();

        Object object = Proxy.newProxyInstance(loader, interfaces, handler);
        return object;
    }

    public class IFactoryInvocationHandler implements InvocationHandler {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("IFactoryInvocationHandler invoke Before!!!");
            Object rtn = method.invoke(object, args);
            System.out.println("IFactoryInvocationHandler invoke After!!!");
            return rtn;
        }
    }

}

测试类:

package proxy.dynamicproxy;

import proxy.dynamicproxy.v3.Cat;
import proxy.dynamicproxy.v3.IAnimal;
import proxy.dynamicproxy.v3.ProxyUtils;

public class Test {

    @org.junit.Test
    public void v3_common_test() {

        // 实例化代理工具类
        ProxyUtils proxyUtils = new ProxyUtils(new Cat());

        // 创建代理对象
        IAnimal animal = (IAnimal)proxyUtils.createProxyObj();

        // 调用被代理类的方法
        animal.eat();
        System.out.println("========================================================");
        animal.run();
        System.out.println("========================================================");
        animal.sleep();
        System.out.println("========================================================");
    }
}

 运行结果:

IFactoryInvocationHandler invoke Before!!!
Cat eat invoking!!!
IFactoryInvocationHandler invoke After!!!
========================================================
IFactoryInvocationHandler invoke Before!!!
Cat Run invoking!!!
IFactoryInvocationHandler invoke After!!!
========================================================
IFactoryInvocationHandler invoke Before!!!
Cat sleep invoking!!!
IFactoryInvocationHandler invoke After!!!
========================================================

Process finished with exit code 0

3、动态代理原理

JDK动态代理是一种实现代理模式的方式。它利用Java的反射机制,在运行时动态地创建代理对象,实现对目标对象的代理。

JDK动态代理的原理如下:
定义接口:首先需要定义一个接口,用于描述目标对象和代理对象的共同行为。
实现InvocationHandler接口:创建一个实现InvocationHandler接口的代理处理器类,该类负责对目标对象的方法进行代理。
获取代理类:通过java.lang.reflect.Proxy的静态方法newProxyInstance()创建代理类,该方法需要传入ClassLoader、接口数组和InvocationHandler实例。
调用代理对象:通过代理对象调用方法时,实际上是调用InvocationHandler的invoke()方法。
在invoke()方法中,可以进行一些额外的操作,比如在调用目标方法之前进行预处理、在调用目标方法后进行后处理等。

4、总结

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习资料汇总

一 卷积 原来卷积是这么计算的 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/268179286 最核心的部分是要知道&#xff0c;通道数和输出特征图无关&#xff0c;是卷积核的个数&#xff0c;决定了输出特征图的个数

详解 SpringMVC 的 @RequestMapping 注解

文章目录 1、RequestMapping注解的功能2、RequestMapping注解的位置3、RequestMapping注解的value属性4、RequestMapping注解的method属性5、RequestMapping注解的params属性&#xff08;了解&#xff09;6、RequestMapping注解的headers属性&#xff08;了解&#xff09;7、Sp…

ArcGIS Pro怎么解决道路压盖问题

在默认情况下&#xff0c;道路可能会存在低等级道路将高等级道路压盖、在道路连接处不连通的情况&#xff0c;这些问题都可以在ArcGIS Pro内解决&#xff0c;这里为大家介绍一下处理方法&#xff0c;希望能对你有所帮助。 道路分级 在符号系统内&#xff0c;选择唯一值&#x…

集成易点易动管理系统连接更多应用

场景描述&#xff1a; 基于易点易动开放平台能力&#xff0c;无代码集成易点易动与多个应用互通互连&#xff0c;实现固定资产管理数字化、智能化。通过Aboter可搭建业务自动化流程&#xff0c;实现多个应用之间的数据连接。 开放能力&#xff1a; 消息推送&#xff1a; 新…

前端js实现获取指定元素(top,lef,right,bottom)到视窗的距离 ;getBoundingClientRect()获取

getBoundingClientRect()获取元素位置&#xff0c;这个方法没有参数 该函数返回一个Object对象&#xff0c;该对象有6个属性&#xff1a;top,lef,right,bottom,width,height&#xff1b; <div id"box"></div>var objectdocument.getElementById(box); …

计算机组成原理(主存储器的基本组成、 运算器的基本组成、 控制器的基本组成、完成一条指令的三个阶段)

主存储器的基本组成&#xff1a; 这个是读数据操作图&#xff1a; 读入数据与菜鸟驿站的取货流程差不多&#xff1a; 写入数据的过程与读入数据类似&#xff1a; 1、cpu 指明想要写入到那个位置&#xff08;写到MAR中&#xff09; 2、想要写入的数据会放到MDR中 3、c…

Visual Studio中Linux开发头文件intellisense问题的解决办法

文章目录 前言个人环境 SSH到WSL复制文件后记 前言 最近在用我心爱的Visual Studio配合WSL2做一些Linux开发&#xff0c;但是有一个问题&#xff0c;就是当我#include <sys/socket.h>&#xff0c;会提示找不到文件 我尝试了各种姿势&#xff0c;包括修改CMakeSettings.…

Hbase-技术文档-java.net.UnknownHostException: 不知道这样的主机。 (e64682f1b276)

问题描述&#xff1a; 在使用spring-boot操作habse的时候&#xff0c;在对habse进行操作的时候出现这个问题。。 报错信息如下&#xff1a; 第一段报错&#xff1a; 第二段报错&#xff1a; java.net.UnknownHostException: e64682f1b276 问题定位解读&#xff1a; 错误 ja…

FanoutExchange广播(扇形)交换机

目录 一、简介 二、代码展示 父pom文件 pom文件 配置文件 config 生产者 消费者 测试 结果 一、简介 扇型&#xff08;广播&#xff09;交换机&#xff0c;这个交换机没有路由键概念&#xff0c;就算你绑了路由键也是无视的。 这个交换机在接收到消息后&#xff0c;…

Windows安装6s模型

官网给出了详细的安装步骤 第一步&#xff1a;安装编译器 安装GnuWin32&#xff0c;按照提示安装&#xff0c;安装到你想安装的地方&#xff0c;记住目录。 安装G77&#xff0c;下载链接里面的Fort99.zip&#xff0c;将G77文件夹提取到C盘根目录。 将这两个目录的bin目录添加…

LibreOffice新一代的办公软件for Mac/Windows免费版

LibreOffice是一款免费、开源的办公软件套件&#xff0c;可在多个操作系统上运行&#xff0c;包括Windows、Mac和Linux。它提供了一系列功能强大的办公工具&#xff0c;包括文档处理、电子表格、演示文稿、数据库管理等。 LibreOffice的界面简洁直观&#xff0c;与其他流行的办…

python+django+协同过滤算法-基于爬虫的个性化书籍推荐系统(包含报告+源码+开题)

为了提高个性化书籍推荐信息管理的效率&#xff1b;充分利用现有资源&#xff1b;减少不必要的人力、物力和财政支出来实现管理人员更充分掌握个性化书籍推荐信息的管理&#xff1b;开发设计专用系统--基于爬虫的个性化书籍推荐系统来进行管理个性化书籍推荐信息&#xff0c;以…

MacOS软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 MacOS是一种由苹果公司开发的操作系统&#xff0c;专门用于苹果公司的计算机硬件。它被广泛用于创意和专业应用程序&#xff0c;如图像设计、音频和视频编辑等。以下是关于MacOS的详细介绍。 1、MacOS的历史和演变 MacOS最初于…

node.js安装好后测试报错解决

node.js的版本是18.X.X node.js安装好后&#xff0c;执行命令&#xff1a; npm install express -g 报错&#xff01;&#xff01;&#xff01; 解决办法&#xff1a; 看报错是由于权限不够&#xff0c; 所以打开cmd时&#xff0c;以管理员的方式打开 然后再执行命令就OK了…

单片机TVS/ESD二极管防护

TVS 瞬态电压抑制二极管Transient Voltage Suppressor ESD 静电释放二极管 Electro-Static discharge 这两种本质上都是二极管。都是利用了二极管正向导通、反向截止的特性。二极管在反向截止截止条件下&#xff0c;如果电压继续增大&#xff0c;将会引发雪崩&#xff0c;使得…

【LeetCode-中等题】19. 删除链表的倒数第 N 个结点

文章目录 题目方法一&#xff1a;节点加入集合找索引方法二&#xff1a;直接计算长度,然后找出要删除的节点的前一个节点方法三&#xff1a;栈方法四&#xff1a;前后双指针 题目 这题的关键在与两个点 一定要设置一个哑结点&#xff0c;防止删除第一个元素时&#xff0c;导致空…

如何利用SFTP协议远程实现更安全的文件传输 ——【内网穿透】

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《高效编程技巧》《cpolar》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 1. 安装openSSH1.1 安装SSH1.2 启动ssh 2. 安装cpolar2.1 配置termux服务 3. 远程SFTP连接配置3.1 查看生成的随机公…

算法训练阶段总结

目录 0 前置 1 内容回顾 学习组合拳 对复杂度的认识 数据结构&#xff1a; 数组&#xff1a;Array 链表&#xff1a;List 哈希表&#xff1a; 字符串&#xff1a; 栈与队列&#xff1a; 二叉树&#xff1a; 回溯&#xff1a; 贪心&#xff1a; 动态规划&#xff…

java八股文面试[JVM]——类加载器

一、类加载器的概念 类加载器是Java虚拟机用于加载类文件的一种机制。在Java中&#xff0c;每个类都由类加载器加载&#xff0c;并在运行时被创建为一个Class对象。类加载器负责从文件系统、网络或其他来源中加载类的字节码&#xff0c;并将其转换为可执行的Java对象。类加载器…

vscode调试PHP代码

目录 准备工作ssh的连接以及配置调试 准备工作 1.首先你需要下载一个vscode 2.下载模块 你需要在VScode中去下载我们所需的两个模块PHP Debug以及remote -ssh 3.安装对应版本的xdebug 需要在xdebug的官方去进行分析&#xff0c;选择适合你自己版本的xdebug 去往官方&#x…