动态代理初步了解

news2024/10/2 3:32:25

准备案例

需求

模拟某企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时。

分析与实现

定义一个UserService表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。

/**
   模拟用户业务功能
 */
public interface UserService {
    String login(String loginName , String passWord) ;
    void selectUsers();
    boolean deleteUsers();
    void updateUsers();
}

定义一个实现类UserServiceImpl实现UserService,并完成相关功能,且统计每个功能的耗时。 

public class UserServiceImpl implements UserService{
    @Override
    public String login(String loginName, String passWord)  {
        long startTimer = System .currentTimeMillis();
        try {
            Thread.sleep(1000);
            if("admin".equals(loginName) && "1234".equals(passWord)) {
                return "success";
            }
            return "登录名和密码可能有毛病";
        } catch (Exception e) {
            e.printStackTrace();
            return "error";
        }finally{
            long endTimer = System.currentTimeMillis();
            System.out.println("login方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");
        }
        

    }

    @Override
    public void selectUsers() {
        long startTimer = System .currentTimeMillis();
        System.out.println("查询了100个用户数据!");
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            long endTimer = System.currentTimeMillis();
            System.out.println("selectUsers方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");
        }
    }

    @Override
    public boolean deleteUsers() {
        long startTimer = System .currentTimeMillis();
        try {
            System.out.println("删除100个用户数据!");
            Thread.sleep(500);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }finally{
            long endTimer = System.currentTimeMillis();
            System.out.println("deleteUsers方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");
        }
    }

    @Override
    public void updateUsers() {
        long startTimer = System .currentTimeMillis();
        try {
            System.out.println("修改100个用户数据!");
            Thread.sleep(2500);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            long endTimer = System.currentTimeMillis();
            System.out.println("updateUsers方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");
        }
    }
}

 定义测试类,创建实现类对象,调用方法。

public class Test {
    public static void main(String[] args) {

        UserService userService = new UserServiceImpl();
        System.out.println(userService.login("admin", "1234"));
        System.out.println(userService.deleteUsers());
        userService.selectUsers();
        userService.updateUsers();
    }
}

提出问题

业务对象的的每个方法都要进行性能统计,存在大量重复的代码。

使用动态代理解决问题

动态代理

代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的。

关键步骤

1.必须有接口,实现类要实现接口(代理通常是基于接口实现的)。

2.创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。

代理过程

当我们要对login方法进行耗时统计时,先进入代理对象,然后统计开始时间,接着真正执行登录方法,最后统计结束时间,如下图所示:

 代码

接口不用变,修改实现类和测试类,增加一个代理工具类,如下:

public class UserServiceImpl implements UserService{
    @Override
    public String login(String loginName, String passWord)  {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if("admin".equals(loginName) && "1234".equals(passWord)) {
            return "success";
        }
        return "登录名和密码可能有毛病";

    }

    @Override
    public void selectUsers() {
        System.out.println("查询了100个用户数据!");
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean deleteUsers() {
        try {
            System.out.println("删除100个用户数据!");
            Thread.sleep(500);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void updateUsers() {
        try {
            System.out.println("修改100个用户数据!");
            Thread.sleep(2500);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
    public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces, InvocationHandler h)
    参数一:类加载器,负责加载代理类到内存中使用。
    参数二:获取被代理对象实现的全部接口。代理要为全部接口的全部方法进行代理
    参数三:代理的核心处理逻辑
 */
public class ProxyUtil {
    /**
      生成业务对象的代理对象。
     * @param obj
     * @return
     */
    public static <T> T  getProxy(T obj) {
        // 返回了一个代理对象了
        return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 参数一:代理对象本身。一般不管
                        // 参数二:正在被代理的方法
                        // 参数三:被代理方法,应该传入的参数
                       long startTimer = System .currentTimeMillis();
                        // 马上触发方法的真正执行。(触发真正的业务功能)
                        Object result = method.invoke(obj, args);

                        long endTimer = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");

                        // 把业务功能方法执行的结果返回给调用者
                        return result;
                    }
                });
    }
}
public class Test {
    public static void main(String[] args) {
        // 1、把业务对象,直接做成一个代理对象返回,代理对象的类型也是 UserService类型
        UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
        System.out.println(userService.login("admin", "1234"));
        System.out.println(userService.deleteUsers());
        userService.selectUsers();
        userService.updateUsers(); // 走代理
    }
}

动态代理的优点

非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接口本身做代理。

可以为被代理对象的所有方法做代理。

可以在不改变方法源码的情况下,实现对方法功能的增强。

不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。

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

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

相关文章

自然语言处理(NLP)的开发框架

自然语言处理&#xff08;NLP&#xff09;领域有许多开源的框架和库&#xff0c;用于处理文本数据和构建NLP应用程序。以下是一些常见的NLP开源框架及其特点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合…

CSS 布局案例: 2行、多行每行格数不定,最后一列对齐

布局期望的效果如下&#xff1a; 第二行最后一格与第一行最后一格对齐。每行格数不定。自动拉伸填充整个宽度 实现&#xff1a; 一开始打算用display:flex&#xff0c; 自动分散&#xff0c;但是第二行对齐第一行最后一格控制不了。 使用grid fr均分单位控制。 <!DOCTYPE…

word重复上次操作的快捷键的F4没效果了

word重复上次操作的快捷键的F4没效果了 word编辑文档的时候&#xff0c;以前都是用F4快捷键解决重复上次操作的&#xff0c;或者ctrly&#xff0c;现在没效果了&#xff0c;在哪里设置回去呢&#xff1f;也没开什么软件不存在快捷键冲突的&#xff0c;F4键也没坏。咋弄哦&…

MPP和hadoop

同样都可以处理大规模数据的MPP数据库架构与Hadoop体系架构属于不同的技术体系&#xff0c;二者没有直接的相关性&#xff0c;却常常被放在一起进行比较。特别是在企业数据仓库建设中&#xff0c;MPP架构与Hadoop架构代表两类典型的技术路线选型&#xff0c;事实上&#xff0c;…

质因子拆贡献+朴素容斥:1007T3

http://cplusoj.com/d/senior/p/SS231007C 考虑枚举gcd&#xff0c;然后容斥&#xff0c;恰好转至少。 g g g 表示gcd恰好为 d d d&#xff0c; f f f 表示至少为 d d d 显然有 f ( d ) ∑ d ∣ n g ( n ) f(d)\sum_{d|n}g(n) f(d)∑d∣n​g(n)&#xff0c;可以直接莫反成…

[python 刷题] 76 Minimum Window Substring

[python 刷题] 76 Minimum Window Substring 题目&#xff1a; Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no …

抖音品牌如何传播,达人投放规划

面对达人的强大带动和种草能力&#xff0c;没有哪个品牌能够坚定的说“不”。但是想要与达人合作&#xff0c;你真的准备好了吗&#xff0c;今天来分享下抖音品牌如何传播&#xff0c;达人投放规划&#xff01; 一、制定投放规划的前期准备 从规划到实施执行并不是一蹴而就的&a…

uniapp物理键/右滑多次退出应用,再次进入显示白屏的问题

复现方式&#xff1a;安卓多次使用物理返回键或右滑退出应用后&#xff0c; 再次进入有很大机率显示白屏。但是手动杀进程的方式不会出现白屏和后台驻留的方式也不会出现白屏 解决思路&#xff1a;利用后台驻留的方式进行假退出应用&#xff0c;把应用隐藏至后台&#xff0c;这…

【Java】Unsafe应用解析

目录 一.功能介绍 二.如何获取Unsafe对象 1.从getUnsafe静态方法获取 2.通过反射获取单例对象theUnsafe 三.Unsafe常用API操作 3.1.线程调度 3.1.1 多线程锁 3.1.2 多线程CAS操作 3.1.3 线程的挂起和恢复 3.2.内存屏障 3.3.内存管理 3.4.对象操作 3.5.运行时动态创…

2023年中国金属涂胶板行业供需分析:销量同比增长2.8%[图]

金属涂胶板是一种将金属板材表面进行涂覆处理的产品。它通常由金属基材&#xff08;如钢板、铝板&#xff09;和胶粘剂组成&#xff0c;胶粘剂可以是有机胶粘剂、聚合物胶粘剂或其他特殊胶粘剂。 金属涂胶板行业分类 资料来源&#xff1a;共研产业咨询&#xff08;共研网&…

引领创新浪潮:“Polygon探寻新技术、新治理、新代币的未来之路!“

熊市是用来建设的&#xff0c;Polygon Labs一直在利用这漫长的几个月来做到这一点。 Polygon 是最常用的区块链之一&#xff0c;每周约有 150 万用户&#xff0c;每天超过 230 万笔交易&#xff0c;以及数千个 DApp&#xff0c;Polygon 最近面临着日益激烈的竞争。虽然从交易数…

助力精彩亚运,杭州第19届亚运会重保工作圆满完成

10月8日&#xff0c;随着杭州第19届亚运会闭幕会结束&#xff0c;大道云行为期16天的重保工作圆满结束。杭州亚运会向大家呈现了真正的“科技与狠活”&#xff0c;数字火炬手、开幕式AR、数字烟花&#xff0c;令人震撼的科技让线上线下的观众真切体会到数实融合。首轮直播全媒体…

与客户携手共进|博睿数据客户最佳实践精选

博睿数据将在秋季发布新一代一体化智能可观测平台 Bonree ONE&#xff0c;轻盈、有序、精准&#xff0c;更好地帮助企业应对新技术带来的运维压力&#xff0c;更好地实现数字化转型。 2023年10月20日的Bonree ONE秋季产品发布会上&#xff0c;我们将邀请先进客户分享最佳实践经…

ASL集睿致远 MIPI转LVDS芯片 CS5518规格书 PIN to PIN替代GM8775C 工业级标准

CS5518可以PIN to PIN替代GM8775C,不需要更改线路,直接替换,CS5518成本比GM8775C要低,整体方案性价比高.CS5518主要实现将 MIPI DSI 转单/双通道 LVDS功能,MIPI 支持1/2/3/4 通道可选,支持 4Gbps 速率。LVDS 时钟频率154MHz&#xff0c;支持常见的1920*1080分辨率的屏&#xff…

性能监控-linux操作系统计数器

top&#xff1a;实时显示系统中各个进程的资源占用状况 top [选项] 交互式命令 基本视图内容解释 top命令&#xff1a; 第一行队列任务信息 第二行 进程任务信息可以看到运行、休眠、停止、僵死状态的进程个数 第三行&#xff1a;CPU状态信息 %Cpu(s): 0.5 us, 0.4 sy, 0.0…

MOS管各种概念(三个极、沟道、衬底、电流方向、箭头方向、耗尽型和增强型、寄生二极管、封装引脚)

三个极、沟道、衬底 D(Drain)漏极&#xff1a;载流子&#xff08;NMOS为负电荷&#xff0c;PMOS为正电荷&#xff09;离开端。 S(Source)源极&#xff1a;载流子发射端。 G(Gate)栅极&#xff1a;控制MOS开关的管脚。 沟道&#xff1a;D和S之间形成的导电通道。 衬底&#xff…

如何实现chatGPT批量问答,不用token

3分钟&#xff0c;教你做个GPT批量问答还不用token | 有源码 源码链接 解压压缩包&#xff1b;在Pycharm打开这个文件夹 执行 pip install undetected_chromedriver 和 pip install selenium 执行第1到63行代码&#xff0c;后台会自动打开浏览器&#xff0c;需要手动登录账…

全场景流量验证系统 | 京东物流技术团队

本文介绍了一种基于线上流量实现对重构系统进行功能和性能验证的实践方案。针对线上流量如何拦截、如何录制、如何存储、如何回放以及如何发压均作了详细说明&#xff0c;为具有类似需求的读者提供了一种可供参考的思路。 1 业务背景 随着百川项目的启动&#xff0c;中台需要…

XSS原理

原理&#xff1a; 这是一种将任意 Javascript 代码插入到其他Web用户页面里执行以达到攻击目的的漏洞。攻击者利用浏览器的动态展示数据功能&#xff0c;在HTML页面里嵌入恶意代码。当用户浏览改页时&#xff0c;这些潜入在HTML中的恶意代码会被执行&#xff0c;用户浏览器被攻…

串联起深度学习的整体,以及其他领域

1、从模型拟合&#xff08;收敛&#xff09;数据关系出发&#xff1a; 2、f从简单的一层和两层连接开始&#xff0c;发展&#xff1b;被表示成 3、如何判断收敛&#xff1a;,即目标函数 4、如何界定任务&#xff1a;&#xff0c;表示什么&#xff1f;表示什么&#xff1f;&a…