AOP基础-动态代理

news2024/10/7 2:24:05

文章目录

    • 1.动态代理
        • 1.需求分析
        • 2.动态代理的核心
        • 3.代码实例
          • 1.Vehicle.java
          • 2.Car.java
          • 3.Ship.java
          • 4.VehicleProxyProvider.java(动态代理模板)
          • 5.测试使用
    • 2.动态代理深入—横切关注点
        • 1.需求分析
        • 2.四个横切关注点
        • 3.代码实例
          • 1.Cal.java
          • 2.CalImpl.java
          • 3.VehicleProxyProvider02.java
          • 4.测试
    • 3.AOP问题引出
        • 1.问题提出
        • 2.土方法解决
          • 修改VehicleProxyProvider02.java
        • 3.极简AOP
          • 1.SunAOP.java
          • 2.修改VehicleProxyProvider02.java

1.动态代理

1.需求分析

image-20240219204601816

2.动态代理的核心

动态代理主要用于对实现了接口的对象的方法调用前后进行拦截,以执行一些额外的操作,那么就要对这个接口进行动态代理

如安全检查、日志记录、事务处理等,而不需要修改原有类的代码。

3.代码实例
1.Vehicle.java
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public interface Vehicle {
    public void run();
}

2.Car.java
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Car implements Vehicle{
    @Override
    public void run() {
        System.out.println("小汽车在路上running。。。。。。");
    }
}

3.Ship.java
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Ship implements Vehicle {
    @Override
    public void run() {
        System.out.println("大轮船在路上running。。。。。。");
    }
}

4.VehicleProxyProvider.java(动态代理模板)
package com.sxs.spring.proxy;

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

/**
 * @author 孙显圣
 * @version 1.0
 */
public class VehicleProxyProvider {
    //1.一个接口属性,需要使用构造方法传入实现接口的目标对象
    private Vehicle target_vehicle;

    public VehicleProxyProvider(Vehicle target_vehicle) {
        this.target_vehicle = target_vehicle;
    }

    //2.编写方法,使用Java的Proxy类动态创建并返回目标对象的代理对象
    public Vehicle getProxy() {
        //类加载器和接口信息都使用目标对象反射获取即可
        ClassLoader classLoader = target_vehicle.getClass().getClassLoader();
        Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();
        //4.匿名内部类实现接口,返回对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            /**
             * 这个方法是在通过代理对象调用任何接口方法时被自动调用的。它允许在调用目标对象的方法前后执行自定义逻辑
             * @param proxy 代理对象
             * @param method 代理对象要调用的那个方法
             * @param args 方法的参数
             * @return 执行invoke方法后的结果
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //方法前的额外操作
                System.out.println("交通工具开始运行了。。。。。。");
                //调用方法
                Object result = method.invoke(target_vehicle, args);
                //方法后的额外操作
                System.out.println("交通工具停止运行了。。。。。。");
                return result;
            }
        };
        /**
         *     public static Object newProxyInstance(
         *     ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
         *     这个方法有三个参数
         *     ClassLoader loader:用于定义代理类的类加载器(一般使用目标对象的类加载器)
         *     Class<?>[] interfaces:代理类需要实现的接口列表,这使得代理对象可以被安全地转换为这些接口中的任何一个
         *     InvocationHandler h:InvocationHandler接口的实现类(使用匿名内部类传入)
         */
        //3.使用Proxy.newProxyInstance来返回代理对象
        Vehicle proxy = (Vehicle) Proxy.newProxyInstance(classLoader,
                interfaces, invocationHandler);
        return proxy;
    }
}

5.测试使用
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Test {

    @org.junit.jupiter.api.Test
    public void proxy() {
        Vehicle vehicle = new Ship();
        //创建代理类的实例,传入实现了接口的目标对象
        VehicleProxyProvider vehicleProxyProvider = new VehicleProxyProvider(vehicle);
        //获取代理对象
        Vehicle proxy = vehicleProxyProvider.getProxy();
        //使用代理对象执行方法
        proxy.run();
    }
}

image-20240219212314525

2.动态代理深入—横切关注点

1.需求分析

image-20240220092730232

2.四个横切关注点
  • 前置通知
  • 返回通知
  • 异常通知
  • 最终通知
3.代码实例
1.Cal.java
package com.sxs.spring.proxy;

/**
 * 计算数量的接口
 *
 * @author 孙显圣
 * @version 1.0
 */
public interface Cal {
    public double getSub(double num1, double num2);
    public double getSum(double num1, double num2);
}

2.CalImpl.java
package com.sxs.spring.proxy;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class CalImpl implements Cal{
    @Override
    public double getSub(double num1, double num2) {
        System.out.println("方法内部打印:" + (num1 - num2));
        return num1 - num2;
    }

    @Override
    public double getSum(double num1, double num2) {
        System.out.println("方法内部打印:" + (num1 + num2));
        return num1 + num2;
    }
}

3.VehicleProxyProvider02.java
package com.sxs.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class VehicleProxyProvider02 {
    //1.传入目标对象
    private Cal cal;

    public VehicleProxyProvider02(Cal cal) {
        this.cal = cal;
    }

    //2.编写方法获取动态代理对象
    public Cal getProxy() {
        //获取类加载器
        ClassLoader classLoader = cal.getClass().getClassLoader();
        //获取接口信息
        Class<?>[] interfaces = cal.getClass().getInterfaces();
        //4.匿名内部类实现接口返回对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            Object result = null;
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                try {
                    System.out.println("方法执行开始-日志-方法名-" + method.getName()
                            + "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知
                    result = method.invoke(cal, args);
                    System.out.println("方法执行正常结束-日志-方法名-" + method.getName()
                            + "-结果-result=" + result); //2.横切关注点-返回通知
                } catch (Exception e) {
                    System.out.println("方法出现异常-日志-方法名-" + method.getName()
                    + "-异常类型=" + e.getClass().getName()); //3.横切关注点-异常通知
                } finally {
                    System.out.println("方法最终结束-日志-方法名-" +
                            method.getName()); //4.横切关注点-最终通知
                    return result; //返回方法的执行结果
                }
            }
        };
        //3.返回动态代理对象
        Cal proxy = (Cal) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxy; //返回动态代理对象
    }
}

4.测试
    @org.junit.jupiter.api.Test
    public void VehicleProxyProvider02Test() {
        CalImpl cal = new CalImpl();
        VehicleProxyProvider02 vehicleProxyProvider02 = new VehicleProxyProvider02(cal);
        Cal proxy = vehicleProxyProvider02.getProxy();
        proxy.getSub(3,1);
        System.out.println("===========================================");
        proxy.getSum(2,4);
    }

image-20240220100957232

3.AOP问题引出

1.问题提出

image-20240220101224618

2.土方法解决
修改VehicleProxyProvider02.java
package com.sxs.spring.proxy03;

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

/**
 * @author 孙显圣
 * @version 1.0
 */
public class VehicleProxyProvider02 {
    //1.传入目标对象
    private Cal cal;

    public VehicleProxyProvider02(Cal cal) {
        this.cal = cal;
    }

    public void before(Method method, Object[] args) {
        System.out.println("方法执行开始-日志-方法名-" + method.getName()
                + "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知
    }
    public void after(Method method, Object result) {
        System.out.println("方法执行正常结束-日志-方法名-" + method.getName()
                + "-结果-result=" + result); //2.横切关注点-返回通知
    }

    //2.编写方法获取动态代理对象
    public Cal getProxy() {
        //获取类加载器
        ClassLoader classLoader = cal.getClass().getClassLoader();
        //获取接口信息
        Class<?>[] interfaces = cal.getClass().getInterfaces();
        //4.匿名内部类实现接口返回对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            Object result = null;
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                try {
                    before(method, args);
                    result = method.invoke(cal, args);
                    after(method, result);
                } catch (Exception e) {
                    System.out.println("方法出现异常-日志-方法名-" + method.getName()
                    + "-异常类型=" + e.getClass().getName()); //3.横切关注点-异常通知
                } finally {
                    System.out.println("方法最终结束-日志-方法名-" +
                            method.getName()); //4.横切关注点-最终通知
                    return result; //返回方法的执行结果
                }
            }
        };
        //3.返回动态代理对象
        Cal proxy = (Cal) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxy; //返回动态代理对象
    }
}

3.极简AOP
1.SunAOP.java
package com.sxs.spring.proxy03;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class SunAOP {
    public static void before(Method method, Object[] args) {
        System.out.println("方法执行开始-日志-方法名-" + method.getName()
                + "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知
    }

    public static void after(Method method, Object result) {
        System.out.println("方法执行正常结束-日志-方法名-" + method.getName()
                + "-结果-result=" + result); //2.横切关注点-返回通知
    }
}

2.修改VehicleProxyProvider02.java

image-20240220102615893

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

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

相关文章

iOS重签名-超详细,附排错

文章目录 重签名步骤步骤 1: 准备必要的材料步骤 2: 解压 .ipa 文件步骤3:将 Provisioning Profile 复制到 Payload 目录步骤 4: 移除原来的签名步骤 5: 使用新的证书和 Provisioning Profile 进行重签名步骤 6: 重新打包 .ipa 文件步骤 7: 安装和测试得到provisioning file和…

语音转换中的扩散模型——DDDM-VC

DDDM-VC: Decoupled Denoising Diffusion Models with Disentangled Representation and Prior Mixup for Verifed Robust Voice Conversion https://ojs.aaai.org/index.php/AAAI/article/view/29740https://ojs.aaai.org/index.php/AAAI/article/view/29740 1.概述 首先,语…

力扣HOT100 - 142. 环形链表 II

解题思路&#xff1a; public class Solution {public ListNode detectCycle(ListNode head) {Set<ListNode> set new HashSet<>();while (head ! null) {if (!set.add(head)) {return head;}head head.next;}return null;} }

findImg找图工具

findImg 安装 npm install findImg -g 启动 findImg run 介绍 找出当前目录下的所有图片&#xff08;包括svg的symbol格式&#xff09;在浏览器中显示出来 源码 https://github.com/HuXin957/find-img 场景 例如前端项目中的img目录&#xff0c;大家都在往里面放图片&#xff…

k8s 控制器StatefulSet原理解析

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、k8s概述 2、有状态服务和无状态服务…

(自学用)正演理论

基于波动方程如何解决数值频散问题——快速正演方法 NAD方法&#xff1a; 怎样离散/逼近高阶偏导数&#xff08;如何采样&#xff09;&#xff1a; 传统方法是用某一点及其周围点的函数f的线性组合来逼近导数。只有函数值&#xff0c;要想提高精度&#xff0c;压制数值频散就必…

与助听器相关的职业主要有哪些?

助听装置是目前解决听觉障碍的几乎唯一科学的方法。然而助听装置改变的不是听力&#xff0c;而是外界的声音信息。也就是助听装置只能将外界的声音信息改变成能够适应听觉障碍患者听觉动态范围的声音。显然助听器并不知道听觉障碍患者的听觉动态范围是多少&#xff1f;也不知道…

PyTorch and Stable Diffusion on FreeBSD

Stable Diffusion在图像生成领域具有广泛的应用和显著的优势。它利用深度学习和扩散模型的原理&#xff0c;能够从随机噪声中生成高质量的图像。 官网&#xff1a;GitHub - verm/freebsd-stable-diffusion: Stable Diffusion on FreeBSD with CUDA support FreeBSD下难度主要…

数据输入输出流(I/O)

文章目录 前言一、数据输入输出流是什么&#xff1f;二、使用方法 1.DataInputStream类2.DataOutoutStream类3.实操展示总结 前言 数据输入输出流也是将文件输入输出流打包后使用的对象。相比于文件输入输出流&#xff0c;数据输入输出流提供了简单易用的方法去操作不同类型的数…

【系统架构师】-案例考点(一)

1、软件架构设计 主要考点&#xff1a; 质量属性、软件架构风格、软件架构评估、MVC架构、面向服务的SOA架构、 DSSA、ABSD 1.1、质量属性 1、性能:指系统的响应能力&#xff0c;即要经过多长时间才能对某个事件做出响应&#xff0c;或者在某段时间内系统所能处理的事件的…

不同版本vue安装vue-router

vue-router 是vue官网发布的一个插件库&#xff0c;单页面路由。vue 和 vue-router 之间版本也需要对应。 vue2.x版本使用vue-router3.x版本&#xff0c;vue3.x使用vue-router4.x版本&#xff0c;根据自己的需要选择合适的版本 1、可以在安装前查看vue-router版本&#xff0c;…

K8S哲学 - probe 探针

探针分类&#xff1a; liveness probe readiness probe startup probe Liveness Probe&#xff1a;用于检查容器是否还在运行。如果 Liveness Probe 失败&#xff0c;Kubernetes 会杀死容器&#xff0c;然后根据你的重启策略来决定是否重新启动容器。常见的做法是使用与 Readin…

深度学习:Pytorch分布式训练

深度学习&#xff1a;Pytorch分布式训练 简介模型并行数据并行参考文献 简介 在深度学习领域&#xff0c;模型越来越庞大、数据量不断增加&#xff0c;训练这些大型模型越来越耗时。通过在多个GPU或多个节点上并行地训练模型&#xff0c;我们可以显著减少训练时间。此外&#…

Python长时间序列遥感数据处理及在全球变化、物候提取、植被变绿与固碳分析、生物量估算与趋势分析等领域中的应用

植被是陆地生态系统中最重要的组分之一&#xff0c;也是对气候变化最敏感的组分&#xff0c;其在全球变化过程中起着重要作用&#xff0c;能够指示自然环境中的大气、水、土壤等成分的变化&#xff0c;其年际和季节性变化可以作为地球气候变化的重要指标。此外&#xff0c;由于…

安装Hexo上传插件时,使用hexo d 报错“Spawn Failed”

问题如下&#xff1a; 解决方案&#xff1a; 找到deploy的配置文件 将配置文件增加 [user]email xxxx你git的邮箱地址name 你git的用户名 然后执行hexo clean清除一下后&#xff0c;执行hexo d&#xff0c;会弹出让你登录git的账号和密码&#xff0c;登录后就上传成功了。 …

Java 判断两个Date类型的时间是否大于6天

判断两个Date类型的时间是否大于6天 new Date().toInstant() 是获取当前时间&#xff0c;并转换成Instant对象 cardDeviceTrajectoryInfo.getGpstime().toInstant() 是表中最后一条数据的时间&#xff0c;并转换成Instant对象 // 计算两个时间的间隔 long daysBetween ChronoU…

【基础IO】谈谈动静态库(怒肝7000字)

文章目录 前言实验代码样例静态库生成一个静态库归档工具ar静态库的链接 动态库创建动态库加载动态库 动静态链接静态链接动态链接动静态链接的优缺点 前言 在软件开发中&#xff0c;库&#xff08;Library&#xff09;是一种方式&#xff0c;可以将代码打包成可重用的格式&…

隧道代理的优势与劣势分析

“随着互联网的快速发展&#xff0c;网络安全已经成为一个重要的议题。为了保护个人和组织的数据&#xff0c;隧道代理技术逐渐成为网络安全的重要工具。隧道代理通过在客户端和服务器之间建立安全通道&#xff0c;加密和保护数据的传输&#xff0c;有效地防止黑客入侵和信息泄…

docker安装并跑通QQ机器人实践(4)-bs-cqhttp搭建

go-cqhttp&#xff0c;基于 Mirai 以及 MiraiGo 的 OneBot Golang 原生实现&#xff0c;只需简单的配置, 就可以基于 go-cqhttp 使用框架开发&#xff0c;具有轻量, 原生, 高并发, 低占用, 跨平台等特点。 1 go-cqhttp 官网及可执行文件下载链接 go-cqhttp 官网&#xff1a;ht…

如何通过MSTSC连接Ubuntu的远程桌面?

正文共&#xff1a;666 字 12 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面我们介绍了如何通过VNC连接Ubuntu 18.04的远程桌面&#xff08;Ubuntu 18.04开启远程桌面连接&#xff09;&#xff0c;非常简单。但是有小伙伴咨询如何使用微软的远程桌面连接MSTSC&#xff08…