AOP基础-动态代理

文章目录

    • 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

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

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

相关文章

第 2 章:FFmpeg简介

2.1 历史 历史 一些相关术语介绍&#xff1a; 容器&#xff08;Container&#xff09;格式&#xff1a;一种文件封装格式&#xff0c;里边主要包含了流&#xff0c;一般会使用一个特定的后缀名标识&#xff0c;例如.mov、.avi、.wav等。流 &#xff08;Stream&#xff09;&am…

大语言模型隐私防泄漏:差分隐私、参数高效化

大语言模型隐私防泄漏&#xff1a;差分隐私、参数高效化 写在最前面题目6&#xff1a;大语言模型隐私防泄漏Differentially Private Fine-tuning of Language Models其他初步和之前的基线微调模型1微调模型2通过低秩自适应进行微调&#xff08; 实例化元框架1&#xff09; 在隐…

pta L1-063 吃鱼还是吃肉

L1-063 吃鱼还是吃肉 分数 10 全屏浏览 切换布局 作者 陈越 单位 浙江大学 国家给出了 8 岁男宝宝的标准身高为 130 厘米、标准体重为 27 公斤&#xff1b;8 岁女宝宝的标准身高为 129 厘米、标准体重为 25 公斤。 现在你要根据小宝宝的身高体重&#xff0c;给出补充营养的…

浅谈 刷算法题时遇到运行超时异常 的解决办法

文章目录 一、背景介绍二、解决办法2.1 C/C 语言2.2 Java 语言2.2.1 ACM模式下 Java的I/O原理 三、模板详情 一、背景介绍 最近在牛客、leetcode 刷算法题时发现一个奇怪的问题&#xff0c;明明解题思路、所用算法与题解一致&#xff0c;并且在本地IDE运行是通过的&#xff0c…

【HTML】H5新增元素记录

H5 新增元素特性 1. 语义化标签 语义化标签的好处&#xff1a; 对于浏览器来说&#xff0c;标签不够语义化对于搜索引擎来说&#xff0c;不利于SEO的优化 语义化标签&#xff1a; header:头部元素nav&#xff1a;导航section:定义文档某个区域的元素article:内容元素aside…

深度学习:Pytorch分布式训练

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

python学习 | 我有两个dataframe,想通过某1列进行匹配

需求 我有两个dataframe&#xff0c;第1个dataframe A的columns是[‘id’, ‘A’, ‘B’, ‘C’]&#xff0c;第2个dataframe B的columns是[‘id’, ‘1’, ‘2’, ‘3’]&#xff0c;其中’id’列A是B的子集&#xff0c;我想通过’id’列进行匹配&#xff0c;把A给扩充成[‘i…

js 特定索引下拆分字符串并组建成新的字符串数据

要在特定索引处拆分字符串&#xff0c;请使用 slice 方法获取字符串的两个部分&#xff0c;例如 str.slice(0, index) 返回字符串的一部分&#xff0c;但不包括提供的索引&#xff0c;而 str.slice(index) 返回字符串的其余部分。 过程&#xff1a;我们创建一个可重用的变量&a…

「GO基础」目录

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

删除word中下划线的内容

当试卷的题目直接含答案&#xff0c;不利用我们刷题。这时如果能够把下划线的内容删掉&#xff0c;那么将有利于我们复习。 删除下划线内容的具体做法&#xff1a; ①按ctrl H ②点格式下面的字体 ③选择下划线线型中的_____ ④勾选使用通配符并在查找内容中输入"?&qu…

Linux 序列化、反序列化、实现网络版计算器

目录 一、序列化与反序列化 1、序列化&#xff08;Serialization&#xff09; 2、反序列化&#xff08;Deserialization&#xff09; 3、Linux环境中的应用实例 二、实现网络版计算器 Sock.hpp TcpServer.hpp Jsoncpp库 Protocol.hpp 类 Request 类 Response 辅助函…

SQLite数据库中JSON 函数和运算符(二十七)

返回&#xff1a;SQLite—系列文章目录 上一篇:维护SQLite的私有分支&#xff08;二十六&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 ​1. 概述 默认情况下&#xff0c;SQLite 支持 29 个函数和 2 个运算符 处理 JSON 值。还有两个表值函数可用于分解 JSON 字…

程序员自由创业周记#32:新产品构思

程序员自由创业周记#32&#xff1a;新产品构思 新作品 我时常把自己看做一位木匠&#xff0c;有点手艺&#xff0c;能做一些作品养活自己。而 加一、Island Widgets、Nap 就是我的作品。 接下来在持续维护迭代的同时&#xff0c;要开启下一个作品的创造了。 其实早在2022的1…

【C++初阶】List使用特性及其模拟实现

1. list的介绍及使用 1.1 list的介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前…

(2022级)成都工业学院数据库原理及应用实验五: SQL复杂查询

写在前面 1、基于2022级软件工程/计算机科学与技术实验指导书 2、成品仅提供参考 3、如果成品不满足你的要求&#xff0c;请寻求其他的途径 运行环境 window11家庭版 Navicat Premium 16 Mysql 8.0.36 实验要求 在实验三的基础上完成下列查询&#xff1a; 1、查询医生…

漆包线行业你了解多少?专业漆包线行业MES生产管理系统

今天就说说漆包线行业&#xff0c;漆包线是工业电机&#xff08;包括电动机和发电机&#xff09;、变压器、电工仪表、电力及电子元器件、电动工具、家用电器、汽车电器等用来绕制电磁线圈的主要材料。 漆包线上游是铜杆行业&#xff0c;下游是各种消费终端&#xff0c;主要是电…

[大模型]Qwen-Audio-chat FastApi 部署调用

Qwen-Audio-chat FastApi 部署调用 Qwen-Audio 介绍 Qwen-Audio 是阿里云研发的大规模音频语言模型&#xff08;Large Audio Language Model&#xff09;。Qwen-Audio 可以以多种音频 (包括说话人语音、自然音、音乐、歌声&#xff09;和文本作为输入&#xff0c;并以文本作为…

Linux-用户管理类命令实训

查看根目录下有哪些内容 进入/tmp目录&#xff0c;以自己的学号建一个目录&#xff0c;并进入该目录 像是目前所在的目录 在当前目录下&#xff0c;建立权限为741的目录test1 在目录test1下建立目录test2/test3/test4 进入test2&#xff0c;删除目录test3/test4 &#xff08;7&…

Python实现在线翻译工具

Python实现在线翻译工具 使用Python的内置的标准库tkinter和webbrowser&#xff0c;实现一个简单Python在线翻译工具。 tkinter库用来创建一个图形用户界面&#xff08;GUI&#xff09;&#xff0c;webbrowser库用来打开网页。 webbrowser 是 Python 的一个标准库&#xff0…

7.MMD 法线贴图的设置与调教

前期准备 人物 导入温迪模型导入ray.x和ray_controler.pmx导入天空盒time of day调成模型绘制顺序&#xff0c;将天空盒调到最上方给温迪模型添加main.fx材质在自发光一栏&#xff0c;给天空盒添加time of lighting材质 打开材质里的衣服&#xff0c;发现只有一个衣服文件 …