动态代理解决方案

2023-09-19 13:46:51

调用不同对象的相同方法,前后都有相应操作,用动态代理的方案完成.
在这里插入图片描述

package com.hspedu.spring.proxy2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author 45
 * @version 1.0
 * VehicleProxyProvider 该类可以返回一个代理对象.
 */
public class VehicleProxyProvider {

    //定义一个属性
    //target_vehicle 表示真正要执行的对象
    //该对象的类实现了Vehicle接口
    private Vehicle target_vehicle;

    //构造器,要求传进一个实现了该接口的对象
    public VehicleProxyProvider(Vehicle target_vehicle) {
        this.target_vehicle = target_vehicle;
    }

    //编写一个方法,可以返回一个代理对象, 该代理对象可以通过反射机制调用到被代理对象的方法
    //老师解读
    //1. 这个方法非常重要, 理解有一定难度
    public Vehicle getProxy() {

        //得到类加载器
        ClassLoader classLoader =
                target_vehicle.getClass().getClassLoader();

        //得到要代理的对象/被执行对象 的接口信息,底层是通过接口来完成调用
        Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();


        //创建InvocationHandler调用处理器 对象
        //接口不能被实例化,但就要的到其对象,所以使用匿名对象
        //因为 InvocationHandler 是接口,所以我们可以通过匿名对象的方式来创建该对象
        /**
         * 因为是接口里边的,所以此方法是抽象方法,并没有方法体,invoke意为调用
         * public interface InvocationHandler {
         *  public Object invoke(Object proxy, Method method, Object[] args)
         *         throws Throwable;
         * }
         * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
         *
         */

        InvocationHandler invocationHandler = new InvocationHandler() {
            /**
             * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
             * @param o 表示代理对象
             * @param method 就是通过代理对象调用方法时,的哪个方法 代理对象Ship/Car.run()
             * @param args : 表示调用 代理对象.run(xx) 传入的参数
             * @return 表示 代理对象.run(xx) 执行后的结果.
             * @throws Throwable
             */
            @Override
            public Object invoke(Object o, Method method, Object[] args)
                    throws Throwable {

                System.out.println("交通工具开始运行了....");
                //这里是我们的反射基础 => OOP
                //method 是?: public abstract void com.hspedu.spring.proxy2.Vehicle.run()
                //target_vehicle 是? Ship对象
                //args 是null
                //这里通过反射+动态绑定机制,就会执行到被代理对象的方法
                //执行完毕就返回
                Object result = method.invoke(target_vehicle, args);
                System.out.println("交通工具停止运行了....");
                return result;
            }
        };

        /*

          public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

          老师解读
          1. Proxy.newProxyInstance() 可以返回一个代理对象proxy
          2. ClassLoader loader: 类的加载器.
          3. Class<?>[] interfaces 就是将来要代理的对象的接口信息
          4. InvocationHandler h 调用处理器/对象 有一个非常重要的方法invoke
         */
        Vehicle proxy =
                (Vehicle)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

        return proxy;
    }
}

package com.hspedu.spring.proxy2;

import org.junit.jupiter.api.Test;

/**
 * @author 45
 * @version 1.0
 */
public class TestVehicle {

    @Test
    public void run() {
        //OOP基础=>java基础
        Vehicle vehicle = new Ship();
        //动态绑定
        vehicle.run();
    }

    @Test
    public void proxyRun() {
        //创建Ship对象
        Vehicle vehicle = new Car();

        //创建VehicleProxyProvider对象, 并且我们传入的要代理的对象
        VehicleProxyProvider vehicleProxyProvider =
                new VehicleProxyProvider(vehicle);


        //获取代理对象, 该对象可以代理执行方法
        //老师解读
        //1. porxy 编译类型 Vehicle
        //2. 运行类型 是代理类型 class com.sun.proxy.$Proxy9

        Vehicle proxy = vehicleProxyProvider.getProxy();

        System.out.println("proxy的编译类型是 Vehicle");
        System.out.println("proxy的运行类型是 " + proxy.getClass());
        //下面老韩就要给大家解读/debug怎么 执行到 代理对象的 public Object invoke(Object o, Method method, Object[] args)
        //梳理完毕. proxy的编译类型是 Vehicle, 运行类型是 class com.sun.proxy.$Proxy9
        //所以当执行run方法时,会执行到 代理对象的invoke
        //如何体现动态 [1. 被代理的对象 2. 方法]
        proxy.run();
        String result = proxy.fly(10000);
        System.out.println("result=" + result);
    }
}

package com.hspedu.spring.proxy2;

/**
 * @author 45
 * @version 1.0
 * 接口,该接口有run方法
 */
public interface Vehicle {
    public void run();
    public String fly(int height);
}

package com.hspedu.spring.proxy2;

/**
 * @author 45
 * @version 1.0
 */
public class Ship implements Vehicle{
    @Override
    public void run() {
        //System.out.println("交通工具开始运行了....");
        System.out.println("大轮船在水上 running....");
        //System.out.println("交通工具停止运行了....");
    }

    @Override
    public String fly(int height) {
        System.out.println("轮船可以飞翔 高度=" + height);
        return "轮船可以飞翔 高度=" + height;
    }
}

package com.hspedu.spring.proxy2;

/**
 * @author 45
 * @version 1.0
 */
public class Car implements Vehicle{
    @Override
    public void run() {
        //System.out.println("交通工具开始运行了....");
        System.out.println("小汽车在路上 running....");
        //System.out.println("交通工具停止运行了....");
    }

    @Override
    public String fly(int height) {
        System.out.println("小汽车可以飞翔 高度=" + height);
        return "小汽车可以飞翔 高度=" + height;
    }
}

更多推荐

Linux中swap几乎耗尽,但物理内存还有空余的现象

故障现象:产生此现象的原因:swappiness配额设置了偏高的值。还有一个潜在的因素是某个程序因其自身对内存管理的缺陷,形成了zombie进程、且为及时关闭的处理任务还在持续消耗Mem及swap。解决办法:调低swappiness配额值,或者直接将swappiness配额设定为0。查看当前OS中的swappiness

iPhone辐射超标,发布三年突然禁售了

昨晚iPhone15预售大家抢到了吗?虽然13日发布会后大家的反应十分冷静,但身体还是很诚实,官网都排到6-7周以后了...在大伙都争着第一波尝鲜的时候,有一个地方正准备禁售iPhone。不用想肯定是欧盟某个国家啦,这两年的Type-C、应用侧载、可拆卸电池...搞事就没停过。法国数字经济部部长在本周发表的《巴黎人报》

前端用JavaScript实现桑基图(Sankey图)

前端用JavaScript实现桑基图(Sankey图)桑基图(Sankey图),是流图的一种,常用来展示事物的数量、发展方向、数据量大小等,在可视化分析中经常使用。本文,演示如何在前端用JavaScript绘制桑基图。注:本例使用JShaman数据展示JS代码混淆加密流程。先看效果:因为已有成熟的库可用,比如,可以使用

苹果给国内用户提供了最好的5G手机,一机在手畅通全球

在某专家不断胡扯苹果的假5G之时,其实是苹果给国内消费者提供了最好的5G手机,真正实现了一机在手畅通全球,技术永不过时,也不会因此花了冤枉钱,那么iPhone为何是最好的5G手机呢?一、5G技术一直在升级运营商在建设5G的过程中不断发现问题,首先是NSA和SA之争,当初业界认为SA才能完整实现5G的技术特征,NSA则降

SpringBoot接口中如何直接返回图片数据

SpringBoot接口中如何直接返回图片数据目录接口直接返回图片数据起因类似这种根据个人经验优雅的实现图片返回接口直接返回图片数据起因最近在做涉及到分享推广的业务,需要由业务员分享二维码进入推广页面,由于是新项目,前期预算和用量都有限,没有搭建对象存储服务,所以决定使用后台服务动态生成二维码图片直接图片数据并返回。首

Kubernetes学习大纲

Kubernetes(通常缩写为K8s)是一个用于自动化部署、扩展和管理容器化(通常是Docker容器)应用程序的开源平台。以下是一些Kubernetes的核心概念和相关的命令。1.集群(Cluster)和节点(Nodes)集群是Kubernetes的基础单元,由一组节点(物理或虚拟机)组成。命令:kubectlget

外滩大会观察|重估蚂蚁!

点击关注文丨刘雨琦,编丨王一粟“不同品种的小狗排队通过‘实名认证’、刷脸识别不仅能识别人,还能识别狗”。“人脸、虹膜、掌纹都已经不算黑科技,脑纹识别才是真的不可替代。”2023年上海外滩大会上,6G、无人安全检测实验室、脑纹核身、蚁鉴2.0、城市链、AI大脑训练、支付芯......改变未来的十大黑科技在会上齐亮相,充满

python基础学习笔记2

python基础语法python的优点开源、易于维护、可移植易于使用、简单优雅广泛的标准库、功能强大可扩展、可嵌入所有的深度学习框架一般都有一个Python版的接口...python典型应用数据分析:对数据进行清洗、去重、规格化和针对性的分析科学计算常规软件开发人工智能网络爬虫WEB开发python基础语法基础操作#1

BK698CPA15B0 创建了通用电气数字工业发展指数

BK698CPA15B0创建了通用电气数字工业发展指数基于调查研究,通用电气创建了通用电气数字工业发展指数,以跟踪数字化转型的实际进展——从对IIoT的展望到准备好转型。该创始指数在100分制中的总得分为63,表明尽管工业互联网的前景非常强劲,得分为78.3(满分为100),但公司准备程度明显落后,得分为55.2(满分

C++提高编程

C++提高编程本阶段主要针对C++泛型编程和STL技术做详细讲解,探讨C++更深层的使用1模板1.1模板的概念模板就是建立通用的模具,大大提高复用性例如生活中的模板一寸照片模板:PPT模板:模板的特点:模板不可以直接使用,它只是一个框架模板的通用并不是万能的1.2函数模板C++另一种编程思想称为泛型编程,主要利用的技术

Docker Volume(存储卷)

文章目录DockerVolume(存储卷)1.什么是存储卷?2.为什么需要存储卷?3.存储卷的分类1)管理卷Volume方式一:Volume命令操作方式二:-v或者--mount指定方式三:Dockerfile匿名卷小结Docker卷生命周期Docker卷共享2)绑定卷bindmount-v参数创建卷3)临时卷tmpf

热文推荐