Spring之代理模式

1、概念

1.1 介绍

二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

在这里插入图片描述
使用代理后:
在这里插入图片描述
②生活中的代理

  • 广告商找大明星拍广告需要经过经纪人
  • 合作伙伴找大老板谈合作要约见面时间需要经过秘书
  • 房产中介是买卖双方的代理
1.2 相关术语
  • 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
  • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。

2 静态代理

    public interface Calculator {
        int add(int i, int j);
        int sub(int i, int j);
        int mul(int i, int j);
        int div(int i, int j);
    }
    package com.giser.java.spring6.calcu.impl;
    
    import com.giser.java.spring6.calcu.Calculator;
    
    /**
     * @author giserDev
     * @description 基础实现
     * @date 2024-01-06 23:41:55
     */
    public class CalculatorImpl implements Calculator {
        @Override
        public int add(int i, int j) {
            int result = i + j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    
        @Override
        public int sub(int i, int j) {
            int result = i - j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    
        @Override
        public int mul(int i, int j) {
            int result = i * j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    
        @Override
        public int div(int i, int j) {
            int result = i / j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    }

创建静态代理类

    package com.giser.java.spring6.calcu.impl;
    
    import com.giser.java.spring6.calcu.Calculator;
    
    /**
     * @author giserDev
     * @description
     * 提出问题
     *
     * ①现有代码缺陷
     *
     * 针对带日志功能的实现类,我们发现有如下缺陷:
     *
     * - 对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
     * - 附加功能分散在各个业务功能方法中,不利于统一维护
     *
     * ②解决思路
     *
     * 解决这两个问题,核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。
     *
     * ③困难
     *
     * 解决问题的困难:要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。所以需要引入新的技术。
     * @date 2024-01-06 23:43:25
     */
    public class CalculatorLogImpl implements Calculator {
    
        @Override
        public int add(int i, int j) {
    
            System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
    
            int result = i + j;
    
            System.out.println("方法内部 result = " + result);
    
            System.out.println("[日志] add 方法结束了,结果是:" + result);
    
            return result;
        }
    
        @Override
        public int sub(int i, int j) {
    
            System.out.println("[日志] sub 方法开始了,参数是:" + i + "," + j);
    
            int result = i - j;
    
            System.out.println("方法内部 result = " + result);
    
            System.out.println("[日志] sub 方法结束了,结果是:" + result);
    
            return result;
        }
    
        @Override
        public int mul(int i, int j) {
    
            System.out.println("[日志] mul 方法开始了,参数是:" + i + "," + j);
    
            int result = i * j;
    
            System.out.println("方法内部 result = " + result);
    
            System.out.println("[日志] mul 方法结束了,结果是:" + result);
    
            return result;
        }
    
        @Override
        public int div(int i, int j) {
    
            System.out.println("[日志] div 方法开始了,参数是:" + i + "," + j);
    
            int result = i / j;
    
            System.out.println("方法内部 result = " + result);
    
            System.out.println("[日志] div 方法结束了,结果是:" + result);
    
            return result;
        }
    }

静态代理的问题:

静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代码,日志功能还是分散的,没有统一管理。

提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。

3 动态代理

在这里插入图片描述

package com.giser.spring6.calcu.impl.dynamicproxy;

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

/**
 * @author giserDev
 * @description 代理工厂类
 * @date 2024-01-06 23:52:21
 */
public class DynamicProxyFactory {

    /**
     * 被持有的被代理对象
     */
    private Object target;

    public DynamicProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 创建代理对象
     * @return 代理对象
     */
    public Object getProxy(){
        return Proxy.newProxyInstance(
                // 代理对象的类加载器
                target.getClass().getClassLoader(),
                // 代理对象实现的接口列表
                target.getClass().getInterfaces(),
                // 处理器
                new InvocationHandler() {
                    /**
                     *
                     * @param proxy the proxy instance that the method was invoked on
                     *              代理对象
                     *
                     * @param method the {@code Method} instance corresponding to
                     * the interface method invoked on the proxy instance.  The declaring
                     * class of the {@code Method} object will be the interface that
                     * the method was declared in, which may be a superinterface of the
                     * proxy interface that the proxy class inherits the method through.
                     *               代理对象需要实现的方法
                     *
                     * @param args an array of objects containing the values of the
                     * arguments passed in the method invocation on the proxy instance,
                     * or {@code null} if interface method takes no arguments.
                     * Arguments of primitive types are wrapped in instances of the
                     * appropriate primitive wrapper class, such as
                     * {@code java.lang.Integer} or {@code java.lang.Boolean}.
                     *             method对应的方法参数
                     *
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result = null;
                        try {
                            System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
                            result = method.invoke(target, args);
                            System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
                        } catch (Exception e) {
                            e.printStackTrace();
                            System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());
                        } finally {
                            System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
                        }
                        return result;
                    }
                }
        );
    }

}

测试

package com.giser.spring6;

import com.giser.spring6.calcu.Calculator;
import com.giser.spring6.calcu.impl.CalculatorImpl;
import com.giser.spring6.calcu.impl.dynamicproxy.DynamicProxyFactory;

/**
 * @author giserDev
 * @description 动态代理测试
 * @date 2024-01-07 00:02:54
 */
public class DynamicProxyTest {

    public static void main(String[] args) {
        DynamicProxyFactory dynamicProxyFactory = new DynamicProxyFactory(new CalculatorImpl());
        Calculator proxy = (Calculator) dynamicProxyFactory.getProxy();
        int add = proxy.add(1, 3);
    }

}

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

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

相关文章

互联网分布式应用之SpringCloud

SpringCloud Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. 微服务项目介绍 2. Eure…

C++ goto语句

作用:可以无条件跳转语句,类似计算机组成原理mips指令集中的jump直接跳转指令(汇编语言)。 语法:goto标记; 解释:如果标记的名称存在,执行到goto语句时,会跳转到标记的…

小游戏实战丨基于PyGame的贪吃蛇小游戏

文章目录 写在前面PyGame贪吃蛇注意事项系列文章写在后面 写在前面 本期内容:基于pygame的贪吃蛇小游戏 下载地址:https://download.csdn.net/download/m0_68111267/88700188 实验环境 python3.11及以上pycharmpygame 安装pygame的命令:…

python实现windows内存看门狗程序(带GUI界面)

python实现windows内存看门狗程序(带GUI界面) 效果图 1、程序核心 看门狗程序核心: 1、运行特定程序任务进程 2、监控任务管理器上的内存使用率 3、如果超过阈值则关闭该特定程序进程 4、重新开启该特定程序 5、重复过程2持续监控2、程序流…

Spring Boot 基础知识点1 (含面试题1)

Spring Boot 是一款基于 Spring 框架的开源应用程序开发工具,它旨在简化 Spring 应用程序的配置和开发过程。Spring Boot 提供了一种简单的方式来创建可独立运行的、生产级别的应用程序,并在需要时进行部署。Spring Boot 在微服务架构和云计算环境下得到…

thinkphp6实现简单定时任务

thinkphp6实现定时任务 创建定时任务文件定义指令编写Test.php代码运行测试 创建定时任务文件 Test类名根据自己的需要修改 php think make:command Test testcommand文件夹在app目录下没有需要自己创建 运行上面的命令后会在command下 多一个Test.php文件 定义指令 在conf…

PHP代码审计之实战审代码篇2

4. 仔细观察如下代码&#xff0c;思考代码有什么缺陷&#xff0c;可能由此引发什么样的问题&#xff1f; <?php require_once("/home/rconfig/classes/usersession.class.php"); require_once("/home/rconfig/classes/ADLog.class.php"); require_onc…

金和OA C6 SAP_B1Config.aspx 未授权漏洞

产品介绍 金和网络是专业信息化服务商,为城市监管部门提供了互联网监管解决方案,为企事业单位提供组织协同OA系统开发平台,电子政务一体化平台,智慧电商平台等服务。 漏洞描述 金和OA C6 SAP_B1Config.aspx接口 未授权&#xff0c;攻击者可通过此漏洞获取数据库账户密码等敏…

2024最新前端源码分享(附效果图及在线演示)

分享10款非常有趣的前端特效源码 其中包含css动画特效、js原生特效、svg特效以及小游戏等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源 粒子文字动画特效 基于canvas实现的粒子文字动画特效 会来回切换设定的文字特效 图…

postman使用方法指南,最全面的教程

Postman使用教程 一、Postman介绍 ​ Postman是一个英语单词&#xff0c;名词&#xff0c;作名词时意为“邮递员&#xff1b;邮差”。 ​ Postman是一个接口测试工具,在做接口测试的时候,Postman相当于一个客户端,它可以模拟用户发起的各类HTTP请求,将请求数据发送至服务端,…

【两阶段鲁棒】计及需求响应的多能互补微网两阶段鲁棒优化matlab

目录 1 主要内容 算例模型 目标函数 第一阶段 第二阶段 求解流程图 2 部分程序 3 程序结果 4 下载链接 1 主要内容 该程序参考文献《多能互补微网两阶段鲁棒优化调度研究》&#xff0c;在考虑风光不确定集的基础上提出采用计及DR响应的多能互补微网两阶段鲁棒备用调度模…

ShardingSphere-JDBC学习笔记

引言 开源产品的小故事 Sharding-JDBC是2015年开源的&#xff0c;早期的定位就是一个分布式数据库的中间件&#xff0c;而在它之前有一个MyCat的产品。MyCat也是从阿里开源出来的&#xff0c;作为分库分表的代名词火了很长一段时间&#xff0c;而MyCat早年的目标就是想进入ap…

Python的基础练习题之学生管理系统

需求 使用Python基础写一个基于控制台的学生管理平台&#xff0c;里面功能分别是&#xff1a;1.录入学生信息2.查找学生信息3.删除学生信息4.修改学生信息5.排序6.统计学生总人数7.显示所有学生信息&#xff0c;要求数据存储在文件里。 代码 代码资源地址可以直接下载 效果图…

消除字母Scratch-第14届蓝桥杯Scratch省赛真题第6题

6. 消除字母&#xff08;100分&#xff09; 编程实现&#xff1a;消除字母。 具体要求&#xff1a; 1). 点击绿旗&#xff0c;角色、背景如图所示&#xff08;创建1个字母表&#xff0c;并存入26个字母&#xff09;&#xff1b; 2). 等待1秒&#xff0c;阿拉蕾说&#xff1…

华为VRP系统基础华为ICT网络赛道

目录 1.华为VRP系统概述 3.2.命令视图与使用 3.3.基本配置命令 1.华为VRP系统概述 通用路由平台VRP(Versatile Routing Platform)是华为公司数据通信产品的通用操作系统平台。它以IP业务为核心&#xff0c;采用组件化的体系结构&#xff0c;在实现丰富功能特性的同时&#x…

AIGC学习笔记(1)——AI大模型提示词工程师

文章目录 AI大模型提示词工程师1 Prompt工程之原理1.1 AIGC的发展和产业前景前言AIGC时代的到来发展趋势和应用展望 1.2 大模型的类型和特点大模型的对比上手特点 1.3 大模型技术原理和发展成语接龙和暴力穷举ChatGPT如何理解人类语言如何存储数据图像存储电脑存数字如何让电脑…

【Docker基础二】Docker安装Mysql8

下载镜像 安装mysql&#xff08;版本&#xff1a;8.0.35&#xff09; # 拉取镜像 docker pull mysql:8.0.35 # 查看镜像是否已经下载 docker images 创建挂载目录 # 宿主机上创建挂载目录 (可以不创建&#xff0c;docker run -v配置了挂载目录&#xff0c;docker会自动…

ARMv8-AArch64 的异常处理模型详解之异常等级、执行状态以及安全状态

ARMv8-AArch64 的异常处理模型详解 一&#xff0c;特权和异常等级1.1 异常等级 Exception levels 二&#xff0c;特权的类型2.1 内存特权2.2 访问寄存器的特权 三&#xff0c;执行状态和安全状态3.1 执行状态 Execution states3.2 执行状态切换 3.3 安全状态 Security states3.…

商品期货交易中的强行平仓:交易所的规定和风险控制

在商品期货交易中&#xff0c;保证金充足的情况下&#xff0c;一般不会被强行平仓。然而&#xff0c;有几种情况可能会导致强行平仓的发生&#xff1a; 1 持仓超过交易所限仓规定&#xff1a;交易所会设定限仓规定&#xff0c;限制每位投资者的持仓数量。如果超过限仓规定&…

CAD安装教程

CAD安装教程 目录 一&#xff0e; 下载CAD二&#xff0e; 安装CAD 一&#xff0e; 下载CAD 如果需要CAD安装包请私信。 二&#xff0e; 安装CAD 解压压缩包AutoCAD2022中文版&#xff0c;以管理员身份运行AutoCAD_2022_Simplified_Chinese_Win_64bit_dlm.sfx。 选择解压路径。…