Java反射的应用:动态代理

news2024/9/22 9:43:44

代理设计模式的原理

使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

对于静态代理,特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能。

动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。

动态代理使用场合:调试、远程方法调用。

动态代理相比于静态代理的优点:抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

动态代理相关API

Proxy:专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。

提供用于创建动态代理类和动态代理对象的静态方法。

static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)创建一个动态代理类所对应的Class对象;

static Object newProxyInstance(

        ClassLoader loader,

        Class<?>[] interfaces,

        InvocationHandler h)

直接创建一个动态代理对象;

loader:类加载器

interfaces:得到被代理类实现的全部接口

h:得到InvocationHandler接口的实现类实例

动态代理步骤

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。

/**
 * @Param theProxy 代理类的对象
 * @Param method 要调用的方法
 * @Param params 方法调用时所需要的参数
 */
public Object invoke(Object theProxy, Method method, Object[] params) throws Throwable{
    try{
        Object retval = method.invoke(targetObj, params);
        // Print out the result
        System.out.println(retval);
        return retval;
    }catch (Exception exc){
    }
}

2.创建被代理的类以及接口

 3.通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个Subject接口代理。

RealSubject target = new RealSubject();
// Create a proxy to wrap the original implementation
DebugProxy proxy = new DebugProxy(target);
// Get a reference to the proxy through the Subject interface
Subject sub = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),new Class[] { Subject.class }, proxy);

4.通过 Subject代理调用RealSubject实现类的方法

String info = sub.say("zhangsan", 24);
System.out.println(info);

动态代理与AOP(Aspect Orient Programming)

前面介绍的Proxy和InvocationHandler,很难看出这种动态代理的优势,下面介绍一种更实用的动态代理机制。

改进后的说明:代码段1、代码段2、代码段3和深色代码段分离开了,但代码段1、2、3又和一个特定的方法A耦合了!最理想的效果是:代码块1、2、3既可以执行方法A,又无须在程序中以硬编码的方式直接调用深色代码的方法。

1.创建一个实现接口InvocationHandler的类

public class MyInvocationHandler implements InvocationHandler{
    // 需要被代理的对象
    private Object target;
    public void setTarget(Object target){
        this.target = target;
    }
    // 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Exception{
        DogUtil du = new DogUtil();
        // 执行DogUtil对象中的method1。
        du.method1();
        // 以target作为主调来执行method方法
        Object result = method.invoke(target , args);
        // 执行DogUtil对象中的method2。
        du.method2();
        return result;
    }
}
public class DogUtil{
    public void method1(){
        System.out.println("=====模拟通用方法一=====");
    }
    public void method2(){
        System.out.println("=====模拟通用方法二=====");
    }
}

2.创建被代理的类以及接口

public interface Dog{
    void info();
    void run();
}
public class HuntingDog implements Dog{
    public void info(){
        System.out.println("一只猎狗");
    }
    public void run(){
        System.out.println("可以奔跑");
    }
}

3.为指定target生成动态代理对象。

public class MyProxyFactory{
    // 为指定target生成动态代理对象
    public static Object getProxy(Object target) throws Exception{
        // 创建一个MyInvokationHandler对象
        MyInvokationHandler handler = new MyInvokationHandler();
        // 为MyInvokationHandler设置target对象
        handler.setTarget(target);
        // 创建、并返回一个动态代理对象
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces() , handler);
    }
}

4.通过代理调用实现类的方法

public class Test{
    public static void main(String[] args) throws Exception{
        // 创建一个原始的HuntingDog对象,作为target
        Dog target = new HuntingDog();
        // 以指定的target来创建动态代理
        Dog dog = (Dog)MyProxyFactory.getProxy(target);
        dog.info();
        dog.run();
    }
}

使用Proxy生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有太大的意义。通常都是为指定的目标对象生成动态代理。

这种动态代理在AOP中被称为AOP代理,AOP代理可代替目标对象,AOP代理包含了目标对象的全部方法。但AOP代理中的方法与目标对象的方法存在差异:AOP代理里的方法可以在执行目标方法之前、之后插入一些通用处理。

 

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

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

相关文章

基于FPGA的按键消抖

文章目录 基于FPGA的按键消抖一、按键消抖原理二、按键消抖代码三、仿真代码编写四&#xff1a;总结 基于FPGA的按键消抖 一、按键消抖原理 按键抖动&#xff1a;按键抖动通常的按键所用开关为机械弹性开关&#xff0c;当机械触点断开、闭合时&#xff0c;由于机械触点的弹性…

怎么使用Netty解码自定义通信协议

网络协议的基本要素 一个完备的网络协议需要具备哪些基本要素 魔数&#xff1a;魔数是通信双方协商的一个暗号&#xff0c;通常采用固定的几个字节表示。魔数的作用是防止任何人随便向服务器的端口上发送数据。协议版本号&#xff1a;随着业务需求的变化&#xff0c;协议可能…

SAP顾问生涯闲记:在SAP工作是什么体验

又有一段时间没更新自己的公众号了&#xff0c;为什么突然决定新开一篇SAP顾问生涯闲记系列的文章呢&#xff0c;是因为最近很荣幸地当选了SAP雇主品牌推广大使&#xff0c;作为SAP官方的推广大使在收获这份荣誉的同时&#xff0c;也承担了一些工作以及责任。 集结完毕︱SAP雇…

Flask_实现token鉴权

目录 1、安装依赖 2、实现代码 3、测试 源码等资料获取方法 1、安装依赖 pip install flask pip install pycryptodome 2、实现代码 import random import string import time import base64from functools import wrapsfrom flask import Flask, jsonify, session, req…

苍穹外卖day02——员工管理功能代码开发+分类管理代码导入

目录 新增员工——需求分析与设计 产品原型 接口设计: 数据库设计: 新增员工——代码开发 在Controller层中 在Service层中 在Mapper层中 功能测试 接口文档测试: 前后端联调测试: 新增员工——代码完善 ​编辑 第一个问题 第二个问题 员工分页查询 需求分析与设计 …

PostgreSQL考试难不难 ?

当涉及到PostgreSQL考试的详细难度&#xff0c;以下是一些可能涉及的主题和考点&#xff0c;这些主题在不同的考试中可能有所不同&#xff1a; 1.数据库基础知识&#xff1a;数据库的基本概念、关系型数据库模型、表、字段、主键、外键等。 2.SQL语言&#xff1a;对SQL语言的掌…

数据集——个人收集标注与使用过的数据集

前言 这是一个我个人在工作和学习中使用过以数据集的一部分&#xff0c;有语义分割&#xff0c;目标识别&#xff0c;人像抠图等几个大类&#xff0c;这只是我用过数据集中的一部分&#xff0c;这些数据集有小一部分是来源自网络&#xff0c;很大一部分都是我自己收集。 一、…

【动手学深度学习】--05.权重衰退

文章目录 权重衰退1.原理1.1使用均方范数作为硬性限制1.2使用均方范数作为柔性限制1.3对最优解的影响1.4参数更新法则 2.从零开始实现权重衰退2.1初始化模型参数2.2定义L2范数惩罚2.3训练2.4忽略正则化直接训练2.5使用权重衰退 3.简洁实现 权重衰退 学习视频&#xff1a;权重衰…

在网格化数据集上轻松执行 2D 高通、低通、带通或带阻滤波器研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

ModaHub魔搭社区:AI原生云向量数据库Zilliz Cloud设置白名单

目录 前提条件 操作步骤 下一步 在 Zilliz Cloud 中,白名单是针对项目的安全设置,适用于项目下的所有集群。设置白名单后,仅白名单中的 IP 地址可以访问您项目下的所有集群。白名单能够有效降低受到恶意攻击的风险 本教程将介绍如何设置白名单。 前提条件 确保满足以…

EasyX测试布局代码

#include <iostream> #include <algorithm> #include <graphics.h> // 引用图形库头文件 #include <conio.h> #include <unordered_map> #include <Windows.h> #include "layout/LayoutSystem.h"#define DEFAULT_PANELS_LAYOUT…

谈二级索引

前提&#xff1a; 在数据库中&#xff0c;1、索引分为聚簇索引和非聚簇索引两类。2、所有索引的数据结构都是树&#xff0c;查找树上的节点数据时通过用二分法来锁定数据范围&#xff0c;指定数据排序的规则&#xff0c;比如&#xff1a;有小到大&#xff0c;对比之后最终确定…

Sequencer使用心得

在关卡序列中设置了触发蓝图的关键帧&#xff0c;为什么播放的时候没有触发蓝图事件呢&#xff1f; 在关卡序列中触发蓝图&#xff0c;一般是将蓝图添加到轨道中&#xff0c;设置触发器&#xff0c;在对应的关键帧中&#xff0c;绑定蓝图事件。 一般的话&#xff0c;点击播…

栈、队列、优先级队列详解【c++】

目录 &#x1f3c0;stack的介绍和使用⚽stack的介绍⚽stack的使用 &#x1f3c0;queue的介绍和使用⚽queue的介绍⚽queue的使用 &#x1f3c0;priority_queue的介绍和使用⚽priority_queue的介绍⚽priority_queue的使用 &#x1f3c0;总结 &#x1f3c0;stack的介绍和使用 ⚽s…

尝试-InsCode Stable Diffusion 美图活动一期

一、 Stable Diffusion 模型在线使用地址&#xff1a; https://inscode.csdn.net/inscode/Stable-Diffusion 二、模型相关版本和参数配置&#xff1a; 活动地址 三、图片生成提示词与反向提示词&#xff1a; 提示词&#xff1a;realistic portrait painting of a japanese…

OPENMV的形状和颜色组合识别

使用openmv&#xff0c;通过阈值颜色和形状来去真假宝藏。调试过程发现颜色的阈值比较重要&#xff0c;因为不准的话&#xff0c;它会把一些颜色相近的物体也识别了。识别的精度有待提高&#xff0c;可以使用YOLOV5来精确识别&#xff0c;奈何本人没精力来弄这个。 打开机器视觉…

Proxmox VE 为 Windows 虚拟机添加硬盘遇到的问题

环境&#xff1a;PVE 8.x、Windows 11/Windows Server 2019 &#x1f449;问题一&#xff1a; 为 windows 虚拟机添加磁盘&#xff0c;重启虚拟机后&#xff08;在 windows 系统中重启&#xff09;磁盘未能生效&#xff0c;并显示为橘色。 ❗橘色 意味需要重启VM才能生效&…

BIO实战、NIO编程与直接内存、零拷贝深入辨析-02

网络通信编程基本常识 什么是 Socket &#xff1f; Socket 是应用层与 TCP/IP 协议族通信的中间软件抽象层&#xff0c;它是一组接口&#xff0c;一般由操作 系统提供。在设计模式中&#xff0c;Socket 其实就是一个门面模式&#xff0c;它把复杂的 TCP/IP 协议处理和…

RocketMQ学习笔记(基础篇)

目录 RocketMQ简介 单Master模式 多Master模式 多Master多Slave模式&#xff08;异步&#xff09; 多Master多Slave模式&#xff08;同步&#xff09; 双主双从集群 事务消息 事务消息发送及提交 事务补偿 事务消息状态 RocketMQ高级功能 消息存储 存储介质 消息的…