Java的静态代理与jdk动态代理

代理

我们经常利用代理进行解耦以及控制对实际对象的访问等工作。例如,我们可以通过代理对方法的调用进行更精细的控制(例如加上日志、权限控制等),而无需修改实际对象的代码。代理的作用是无侵入式的给代码增加功能。有些事情是对象不想做或者不能做的,就可以通过代理来实现。
代理一般有三种模式:

  1. 静态代理
  2. jdk动态代理
  3. cglib动态代理(这里不做过多赘述)

静态代理

静态代理很简单,我们通过代码来理解就很方便。

package TestProcxy;

public class ProTest {
    public static void main(String[] args) {
        Father father = new Father();
        father.eat();
    }
}

class Per{
    public void eat(){
        System.out.println("吃饭!!!");
    }
}

class Father{
    Per per = new Per();
    public void eat(){
        System.out.println("拿筷子~~~~");
        per.eat();
        System.out.println("洗碗~~~~");
    }
}

运行结果
![[Pasted image 20240329095713.png]]

jdk动态代理

代理里面就是对象要被代理的方法。java通过接口来保证代理的样子,即对象和代理要实现同一个接口中的方法就是被代理的所有方法。
代理可以增强或者拦截的方法都在接口中,接口需要写在newProxyInstance的第二个参数里。

package TestProxy;

/**
 * 接口
 * 通过接口来进行代理
 */
public interface Event {
    void eat(String something);
}


package TestProxy;

public class Per implements Event {
    String name;

    public Per(String name) {
        this.name = name;
    }
    @Override
    public void eat(String something) {
        System.out.println(name + "吃" + something + "!!!");
    }
}


package TestProxy;

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

public class PerProxy {
    public static Event createProxy(){
        /**
         * java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
         * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
         * 参数一:用于指定用哪个类加载器去加载生成的代理类
         * 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
         * 参数三:用来指定生成的代理对象要干什么事情
         */
        Object o = Proxy.newProxyInstance(
                PerProxy.class.getClassLoader(),
                new Class[]{Event.class},
                new InvocationHandler() {
                    /*
                     * 参数一:代理的对象
                     * 参数二:要运行的方法 eat
                     * 参数三:调用eat方法时,传递的实参
                     * */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("拿筷子~~~");
                        method.invoke(new Per("张三"), args);
                        System.out.println("洗碗~~~");
                        return null;
                    }
                });
        return (Event) o;
    }
}


package TestProxy;

public class ProTest {
    public static void main(String[] args) {
        PerProxy perProxy = new PerProxy();
        Event proxy = perProxy.createProxy();
        proxy.eat("刀削面");
    }
}

运行结果
![[Pasted image 20240329110824.png]]

练习

对List的add方法进行增强,对remove方法进行拦截。

package TestProxy;

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

public class EnhanceList {
    public static void main(String[] args) {

        List list = new ArrayList();
        Object o = Proxy.newProxyInstance(EnhanceList.class.getClassLoader(), new Class[]{List.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 对原List的add方法进行增强
                if (method.getName().equals("add")) {
                    System.out.println("对list新增了" + args[0]);
                    return method.invoke(list, args);
                } else if (method.getName().equals("remove")) {
                    // 拦截根据索引删除的方法是正常的,如果拦截根据对象删除的方法就会报错,因为他们的返回值不一样
                    System.out.println("拦截了remove方法");
                    return null;
                } else {
                   return method.invoke(list, args);
                }
            }
        });
        List proxyList = (List) o;
        proxyList.add("aaa");
        proxyList.add("bbb");
        proxyList.add("ccc");
        proxyList.add("ddd");

        proxyList.remove(0);
        proxyList.remove("aaa");
        System.out.println(list);
    }
}

这段代码是由问题的就是在拦截remove方法时的问题,因为remove重载了两种方法,返回值类型也不一样(一个是布尔类型,另一个是对象),而我们在拦截时只返回了null,因此会报错。
运行结果
![[Pasted image 20240329114907.png]]

正确的修改
![[Pasted image 20240329115006.png]]

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

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

相关文章

【分布式】——CAPBASE理论

CAP&BASE理论 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/tree-learning-notes ⭐⭐⭐⭐⭐⭐ Spring专栏&#x1f449;https://blog.csdn.net/weixin_53580595/category_12279588.html Sprin…

物联网实战--入门篇之(一)物联网概述

目录 一、前言 二、知识梳理 三、项目体验 四、项目分解 一、前言 近几年很多学校开设了物联网专业&#xff0c;但是确却地讲&#xff0c;物联网属于一个领域&#xff0c;包含了很多的专业或者说技能树&#xff0c;例如计算机、电子设计、传感器、单片机、网…

C++万物起源:类与对象(二)

一、类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f; 并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员 函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;…

DataX-Oracle新增writeMode支持update

目录 前言 第一步下载源码 第二步修改源码 1、Oraclewriter 2、WriterUtil 2.1、修改getWriteTemplate方法 2.2、新增onMergeIntoDoString与getStrings方法 3、CommonRdbmsWriter 3.1、修改startWriteWithConnection 3.2、修改doBatchInsert 3.3、修改fillPreparedStatem…

红酒:红酒分类与消费者教育的重要性

在红酒的世界里&#xff0c;品种繁多&#xff0c;口感各异。对于消费者而言&#xff0c;了解红酒的分类以及接受相关的消费者教育至关重要。云仓酒庄雷盛红酒作为业界的持续发展者&#xff0c;深知这一点&#xff0c;致力于为消费者提供品质的教育内容&#xff0c;帮助他们更好…

Verilog语法之case语句学习

case分支语句是一种实现多路分支控制的分支语句。与使用if-else条件分支语句相比&#xff0c;采用case分支语句来实现多路控制会变得更加的方便直观。 case分支语句通常用于对微处理器指令译码功能的描述以及对有限状态机的描述。Case分支语句有“case”、“casez”、“casex”…

MybatisPlus学习总结

MybatisPlus.xmind 一、MybatisPlus快速入门 1.基本介绍 官网: 简介 | MyBatis-Plus MyBatis Plus是一个基于MyBatis的增强工具&#xff0c;它简化了MyBatis的使用&#xff0c;提供了一系列的增强功能&#xff0c;使开发更加方便快捷。 MyBatis Plus的主要特点包括&#xff…

3月23日笔记

广播域与泛洪范围是相同的 广播&#xff1a;在同一个泛洪范围内&#xff0c;强迫交换机泛洪&#xff08;主动&#xff09; 泛洪&#xff08;被动&#xff09; ARP的工作原理&#xff1a;ARP先通过广播发送请求包&#xff0c;所有收到该广播包的设备都会将其中的源IP和源MAC相…

《Vision mamba》论文笔记

原文出处&#xff1a; [2401.09417] Vision Mamba: Efficient Visual Representation Learning with Bidirectional State Space Model (arxiv.org) 原文笔记&#xff1a; What&#xff1a; Vision Mamba: Efficient Visual Representation Learning with Bidirectional St…

【Python】#2 基本数据类型

文章目录 一、数字类型1. 整数类型2. 浮点数类型tips&#xff1a;为什么浮点数计算的小数部分经常“错误”&#xff1f;如 为什么0.10.20.3在计算机中不为真 3. 复数形式<classcomplex>4. 数字类型的操作符与部分函数tips: 数字类型的类型提升tips:Python中除法 基本数据…

电商控价的效果有哪些

品牌在做价格治理时&#xff0c;肯定是不再希望线上平台出现低价、窜货链接&#xff0c;但现实却难如品牌所愿&#xff0c;有几个难以实现的原因&#xff0c;首先&#xff0c;电商平台链接上架下架是很容易的&#xff0c;此刻将链接治理下架&#xff0c;下一刻店铺可能又会再上…

《QT实用小工具·二》图片文字转base64编码

1、概述 源码放在文章末尾 base64编码转换类 图片转base64字符串。base64字符串转图片。字符转base64字符串。base64字符串转字符。后期增加数据压缩。Qt6对base64编码转换进行了重写效率提升至少200%。 下面是demo演示&#xff1a; 项目部分代码如下所示&#xff1a; #ifn…

python pytz是什么

pytz模块常用于时区的转换&#xff0c;常常配合datetime一起使用。我们知道datetime除了data方法生成的时间是没有时区概念&#xff0c;其他如time、datetime等都是有时区概念&#xff0c;即指定了tzinfo信息。 >>> import datetime >>> datetime.datetime.n…

【机器学习】深入探讨基于实例的学习及K-最近邻算法

深入探讨基于实例的学习及K-最近邻算法 在机器学习的众多策略中&#xff0c;基于实例的学习方法因其简单性和高效性而备受关注。这种方法的核心理念在于利用已知的数据实例来预测新数据的标签或属性。本文将深入探讨其中的两个重要概念&#xff1a;最近邻算法和K-最近邻算法&a…

浏览器工作原理与实践--块级作用域:var缺陷以及为什么要引入let和const

在前面《07 | 变量提升&#xff1a;JavaScript代码是按顺序执行的吗&#xff1f;》这篇文章中&#xff0c;我们已经讲解了JavaScript中变量提升的相关内容&#xff0c;正是由于JavaScript存在变量提升这种特性&#xff0c;从而导致了很多与直觉不符的代码&#xff0c;这也是Jav…

考研数学|高效刷透汤家凤《1800》经验分享

当然不需要换老师&#xff0c;如果你在基础阶段连汤老师的课都听不进去&#xff0c;那么换其他老师的话&#xff0c;很大可能也是白搭。 如果你现在对于1800还是一筹莫展的话&#xff0c;那么很明显&#xff0c;这反映出前期基础不扎实&#xff0c;没有真正理解和掌握这部分内…

【NOI】树的初步认识

文章目录 前言一、树1.什么是树&#xff1f;2.树的基本概念3.树的基本术语3.1 节点3.1.1 根节点3.1.2 父节点、子节点3.1.3 兄弟节点、堂兄弟节点3.1.4 祖先节点、子孙节点3.1.5 叶子节点/终端节点3.1.6 分支节点/非终端节点 3.2 边3.3 度3.3.1 树的度 3.4 层次3.4.1 树的深度3…

学习JavaEE的日子 Day32 线程池

Day32 线程池 1.引入 一个线程完成一项任务所需时间为&#xff1a; 创建线程时间 - Time1线程中执行任务的时间 - Time2销毁线程时间 - Time3 2.为什么需要线程池(重要) 线程池技术正是关注如何缩短或调整Time1和Time3的时间&#xff0c;从而提高程序的性能。项目中可以把Time…

磐启微PAN1020低功耗SOC芯片

PAN1020低功耗蓝牙芯片 典型应用 ⚫ 电视和机顶盒遥控器 ⚫ 无线游戏手柄 ⚫ 无线鼠键 ⚫ 智能家居 需要此物料&#xff0c;可联系周小姐 主要特性 ⚫ RF - 2.4GHz 射频收发机&#xff08;兼容 BLE4.2&#xff09; - 接收灵敏度&#xff1a;-90 dBm1Mbps - 接收信号&a…

智慧公厕解决方案打造更加智能的卫生空间

一、智慧公厕方案概述 智慧公厕方案旨在解决现有公厕存在的诸多问题&#xff0c;包括民众用厕困难、环境卫生状况不佳、管理效率低下等方面。针对民众的需求和管理方面的挑战&#xff0c;智慧公厕提供了一套综合解决方案&#xff0c;包括智能导航、环境监测、资源管理等功能&a…
最新文章