动态代理静态代理

news2025/7/8 15:10:45

一、使用背景

将目标类包裹起来,对目标类增加一个前置操作和一个后置操作,比如添加日志,在调用目标类前、调用目标后添加日志。

感觉静态代理与动态代理的核心思想,都是根据目标类,拿到目标实现的接口,和目标类的方法。然后创建一个新的类。然后将自己的前置行为与后置行为填充到这个新的类里。

静态代理,就是我们自己手动去写这个过程

动态代理,就是由java的java.lang.reflect包下提供的一个Proxy类来实现

二、静态代理

实现思路:

举例,类HelloSerivceImpl 实现接口Hello Service。 我想在类HelloSerivceImpl前后添加操作。

则我自定义一个类,同样继承于Hello Service。将目标类作为自定义类的属性,然后将目标类包裹起来,在调用前与调用后,增加步骤。

我们将来再调用的时候,调用的是我们自定义的这个类。

Hello Service

public interface HelloService {
    String hi(String name);
}

HelloSerivceImpl目标类

public class HelloServiceImpl implements HelloService{
    @Override
    public String hi(String name) {
        System.out.println("======");
        return "hi"+name;
    }
}

自定义类

public class HelloProxy implements HelloService{
    private HelloService helloService;

    public HelloProxy(HelloService helloService) {
        this.helloService = helloService;
    }

    @Override
    public String hi(String name) {
        System.out.println("AAAAAA");
        String hi = helloService.hi(name);
        System.out.println("BBBBBBB");
        return hi;
    }
}

调用

public class App {
    public static void main(String[] args) {
        HelloService helloService = new HelloServiceImpl();
        HelloService newHelloService = new HelloProxy(helloService);
        String hi1 = newHelloService.hi("zhangsan");
        System.out.println(hi1);

    }
}

三、动态代理

静态代理遇到的问题:

1、静态代理,只能针对某个具体的接口去写,如果遇到多个接口,需要写多个静态代理

2、上述只写了一个方法,如果扩展成多个方法,还需要加代码。

3、如果目标类实现多个接口呢

动态代理:

1、不需要关心实现了多少个接口

2、不需要关心多少个抽象方法

在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。

同样也是需要收集(传参)目标类实现的接口及方法,才能生成代理类。

举例:

接口HelloService 

public interface HelloService {
    String hi(String name);
}

实现类HelloServiceImpl

public class HelloServiceImpl implements HelloService{
    @Override
    public String hi(String name) {
        return "hi"+name;
    }
}

使用Proxy类实现动态代理

        HelloService helloService = new HelloServiceImpl();

        HelloService helloService1 =(HelloService)Proxy.newProxyInstance(
                helloService.getClass().getClassLoader(),// 类加载器,通过类加载器获取一个新的对象 代理对象
                helloService.getClass().getInterfaces(), // 通过反射,拿到这个对象实现的所有接口
                new InvocationHandler() { // 匿名内部类
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // proxy 代理类,这里用不上
                        // method
                        // args 参数
                        // 原方法前,加自己的方法
                        Object o = method.invoke(helloService, args);// 调用目标类里面的方法,传原来的那个对象
                        // 原方法后,加自己的方法
                        return o;
                    }
                }
        );
        helloService1.hi("张三");

使用匿名内部类实现

        // 匿名内部类
        HelloService helloService2 =(HelloService)Proxy.newProxyInstance(
                helloService.getClass().getClassLoader(),// 类加载器,通过类加载器获取一个新的对象 代理对象
                helloService.getClass().getInterfaces(), // 通过反射,拿到这个对象实现的所有接口
                (proxy, method, args1) -> {
                    // proxy 代理类,这里用不上
                    // method
                    // args 参数
                    // 原方法前,加自己的方法
                    Object o = method.invoke(helloService, args1);// 调用目标类里面的方法,传原来的那个对象
                    // 原方法后,加自己的方法
                    return o;
                }
        );

使用泛型,封装一个公共的方法


    public static <T> T getInstance1(T instance){
        ClassLoader loader = instance.getClass().getClassLoader();
        Object o = Proxy.newProxyInstance(
                instance.getClass().getClassLoader(),
                instance.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("前置操作");
                        Object invoke = method.invoke(instance, args);
                        System.out.println("后置操作");
                        return invoke;
                    }
                }
        );
        return (T) o;
    }

四、扩展:ClassLoader 的作用


我们都知道java程序写好以后是以.java(文本文件)的文件存在磁盘上,然后,我们通过(bin/javac.exe)编译命令把.java文件编译成.class文件(字节码文件),并存在磁盘上。
但是程序要运行,首先一定要把.class文件加载到JVM内存中才能使用的,我们所讲的classLoader,就是负责把磁盘上的.class文件加载到JVM内存中。

在这里插入图片描述

 你可以认为每一个Class对象拥有磁盘上的那个.class字节码内容,每一个class对象都有一个getClassLoader()方法,得到是谁把我从.class文件加载到内存中变成Class对象的。

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

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

相关文章

【软考】-- 操作系统(上)

目录&#xff1a;操作系统&#xff08;上&#xff09;第一节 操作系统概述&#x1f384;一、操作系统基本概念1️⃣操作系统的五大部分&#xff1a;&#x1f38b;二、操作系统的分类1️⃣批处理操作系统&#xff1a;2️⃣分时操作系统&#xff1a;3️⃣实时操作系统&#xff1a…

STC51单片机28——跑马灯

//使用P1口流水点亮8位LED #include<reg51.h> //包含单片机寄存器的头文件 /**************************************** 函数功能&#xff1a;延时一段时间 *****************************************/ void delay(void) { unsigned char i,j; for(i…

Jetpack Compose 重写TopAppBar 实现标题多行折叠

没有效果图一律当水贴处理 效果动图 前言 想用composes实现类似CSDN的文章详细页面的标题栏 上滑隐藏标题后标题栏显示标题 compose.material3下的TopAppBar不能嵌套滚动 MediumTopAppBar 便使用了MediumTopAppBar一开始用着没什么问题&#xff0c;但是标题字数多了&…

一天完成react面试准备

什么是 React的refs&#xff1f;为什么它们很重要 refs允许你直接访问DOM元素或组件实例。为了使用它们&#xff0c;可以向组件添加个ref属性。 如果该属性的值是一个回调函数&#xff0c;它将接受底层的DOM元素或组件的已挂载实例作为其第一个参数。可以在组件中存储它。 ex…

字体图标以及svg图片的使用vite和webpack

先说下字体图标的使用 首先去阿里巴巴矢量图标库&#xff0c;选择你需要的图标&#xff08;可将svg图片自己上传&#xff09;添加到项目里&#xff0c;可以生成在线链接&#xff0c;或者下载资源包到本地。 资源包形式&#xff1a;在项目里创建一个fonts文件夹&#xff0c;将下…

linux 安装rar工具

1.到官网下载对应的编译包 点击跳转 也可以直接到我上传的资源去下载 https://download.csdn.net/download/liudongyang123/87032929https://download.csdn.net/download/liudongyang123/870329292.解压 tar -xf rarlinux-x64-620b2.tar.gz 3.进入到解压后的文件夹&#xf…

Spring Cloud Alibaba 版本对照表,集成nacos,sentinel,seata

一、Spring Cloud Alibaba 版本对照网址 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 二、集成nacos nacos源码编译打包_qq_41369135的博客-CSDN博客 连接mysql nacos\conf下的application.properties spring.datasource.…

JDBC:PreparedStatement 插入BLOB类型的数据,PreparedStatement 批量处理,Connection 事务处理

JDBC&#xff1a;PreparedStatement 插入BLOB类型的数据&#xff0c;PreparedStatement 批量处理&#xff0c;Connection 事务处理 每博一文案 村上春树说: 你要做一个不动声色的大人了&#xff0c;不准情绪化&#xff0c;不准偷偷想念&#xff0c;不准回头看自己&#xff0c;…

VGG网络详解(实现猫猫和狗狗识别)

VGG VGG在2014年由牛津大学著名研究组vGG (Visual Geometry Group)提出&#xff0c;斩获该年lmageNet竞赛中Localization Task (定位任务)第一名和 Classification Task (分类任务)第二名。 感受野 首先介绍一下感受野的概念。在卷积神经网络中&#xff0c;决定某一层输出结…

Cloud Flare 添加谷歌镜像站(反向代理)

1.首先创建一个属于自己的镜像站 参考链接&#xff1a;利用cloudflare搭建属于自己的免费Github加速站 首先&#xff0c;点击 Cloud Flare 链接 &#xff0c;创建一个属于自己的账户 登录后&#xff0c;点击 Workers 这个子域&#xff0c;可以自定义 输入好后点set up 然后…

[附源码]java毕业设计基于实时定位的超市配送业务管理

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

本地外卖市场趋势怎么样?成为行业黑马的机会有多大呢?

随着互联网经济的发展&#xff0c;很多人倾向于足不出户就能吃到各种美味食物&#xff0c;因此外卖行业应运而生。这个新行业不仅解决懒人的饮食问题&#xff0c;也为社会提供了更多的就业机会——外卖配送员。据CNNIC的《2022年第49次中国互联网络发展状况统计报告》显示&…

学会这几款表白特效让你明年双十一不再是一个人

随着各种节日的到来&#xff0c;也伴随着许许多多的表白时机&#xff0c;为何不制作几款表白特效让你的行动更加充实呢&#xff0c;此文主要基于HTMLCSSJS制作网页特效&#xff0c;代码简洁&#xff0c;上手简单。 网页特效爱心画心3D爱心爱在心中3D旋转相册开发流程工具安装创…

C语言,从联合看字节序

C语言中的联合&#xff08;union&#xff09;类型为我们提供了操纵和解读“数据”的独特方式&#xff0c;它允许对同一块内存以不同的方式进行解读和操纵。 union UINT {unsigned int intValue; //占4个字节unsigned char bytes[4]; //占4个字节 }; //注意末尾分号不能少本…

aj-report页面嵌入其他项目

我们前面已经制作了自己的报表,我们可以通过共享报表将结果呈现给其他人,但是对一些小白来说,报表与其他项目合成是一个新的问题。怎么合成呢? 我们继续未完的探索。 1、首先,我们可以创建一个已做好的报表的链接: 如上图,我们可以在报表管理里面分享建成的报表,选…

UnRaid安装CloudDrive以实现阿里云盘、天翼云盘、115网盘挂载

文章目录1、前言2、准备工作2.1、修改Docker源2.2、开启Docker服务的MountFlags功能3、添加Docker应用CloudDrive4、添加云盘1、前言 最近一直在学习UnRaid这个Nas系统&#xff0c;折腾起来易用性十足&#xff0c;但由于其自带的应用市场不能完全满足所有人的需求&#xff0c;…

高纯度高活性艾美捷人重组MEGACD40L蛋白(可溶性)

艾美捷人重组MEGACD40L蛋白&#xff08;可溶性&#xff09;&#xff1a;高活性、高纯度CD40L蛋白&#xff0c;用于免疫应答的共刺激激活。 艾美捷人重组MEGACD40L蛋白&#xff08;可溶性&#xff09;特点&#xff1a; 1、高活性MEGACD40L低聚物模拟体内膜辅助CD40L聚集和刺激&…

【C++修炼之路】9. string类的模拟实现

每一个不曾起舞的日子都是对生命的辜负 string类的模拟实现前言代码&#xff1a;1. string.h2. test.cpp扩展&#xff1a;内置类型的拷贝构造总结前言 本篇文章是衔接上一篇string&#xff0c;进行string的模拟实现&#xff0c;其中包含了众多重载函数&#xff0c;以及一些实现…

pytest中allure特性

一、allure.step allure报告最重要的一点是&#xff0c;它允许对每个测试用例进行非常详细的步骤说明 通过 allure.step() 装饰器&#xff0c;可以让测试用例在allure报告中显示更详细的测试过程 step() 只有一个参数&#xff0c;就是title&#xff0c;你传什么&#xff0c;在…

Linux------网络基础1

文章目录计算机网络的发展历程网络协议计算机网络分层体系结构局域网通信的原理IP地址和 MAC地址的区别计算机网络的发展历程 简单的了解一下就行&#xff0c;图就不提供了。 1&#xff0c;最开始&#xff0c;计算机之间是相互独立的&#xff0c;不能沟通交流。 2&#xff0c;…