java 静态代理和动态代理

2023-11-11

什么是代理

从字面意思来说,代理就是代替处理的意思。
从程序层面来说,代理就是代替某个程序,处理某个事情。

静态代理

场景1: 小明需要买基金。

public class Main {
    public static void main(String[] args) {
        Person xiaoming= new XiaoMing();
        boolean isSuccess = xiaoming.buy();//小明去买基金
        System.out.println("结果"+(isSuccess?"基金大涨":"被割韭菜"));
    }
}
interface Person{
    boolean buy();
}
class XiaoMing implements Person{
    @Override
    public boolean buy() {
        System.out.println("我是小明,我要买基金");
        return false;
    }
}

运行结果

我是小明,我要买基金
结果被割韭菜

场景2: 小明刚买了不久的基金,连跌几天,被割了韭菜,这时候小明找到了一个基金经理,让基金经理帮自己管理基金。

我们新增一个 基金经理的类,并传入一个被代理的人

public class Main {
    public static void main(String[] args) {
        Person fundManager = new FundManager(new XiaoMing()) ;//小明被基金经理代理了
        boolean isSuccess = fundManager.buy();//基金经理去买基金
        System.out.println("结果"+(isSuccess?"基金大涨":"被割韭菜"));
    }
}
interface Person{
    boolean buy();
}
class XiaoMing implements Person{
    @Override
    public boolean buy() {
        System.out.println("我是小明,我要买基金");
        return false;
    }
}
class FundManager implements Person{
    Person person;
    FundManager(Person person){
        this.person = person;
    }
    @Override
    public boolean buy() {
        person.buy();
        System.out.println("我是基金经理,我帮我的用户赚钱");
        return true;
    }
}

运行结果

我是小明,我要买基金
我是基金经理,我帮我的用户赚钱
结果基金大涨

场景3: 小明已经通过基金经理赚了不少钱,他需要卖出一部分,并且开始进行基金定投。

package cn.enncy.scs;
public class Main {
    public static void main(String[] args) {
        Person fundManager = new FundManager(new XiaoMing()) ;
        fundManager.buy();
        fundManager.sell();
        fundManager.autoInvestment();
    }
}
interface Person{
    boolean buy();
    boolean sell();
    boolean autoInvestment();
}
class XiaoMing implements Person{
    @Override
    public boolean buy() {
        System.out.println("我是小明,我要买基金");
        return false;
    }

    @Override
    public boolean sell() {
        System.out.println("我是小明,我要出售基金");
        return false;
    }

    @Override
    public boolean autoInvestment() {
        System.out.println("我是小明,我要定投基金");
        return false;
    }
}
class FundManager implements Person{
    Person person;
    FundManager(Person person){
        this.person = person;
    }
    @Override
    public boolean buy() {
        person.buy();
        System.out.println("我是基金经理,我帮我的用户赚钱");
        return true;
    }

    @Override
    public boolean sell() {
        return person.sell();
    }

    @Override
    public boolean autoInvestment() {
        return person.autoInvestment();
    }
}


结果

我是小明,我要买基金
我是基金经理,我帮我的用户赚钱
我是小明,我要出售基金
我是小明,我要定投基金

我们可以看到,其实定投出售,根本不需要经过基金经理进行代理,自己进行这个操作就行了,所以代码非常冗余,如果不经过基金经理又会被割韭菜。

那要怎么实现,当买基金的时候让基金经理代理,不需要买基金的时候,其他操作自己执行 ?
这时候,动态代理 的优势就体现出来了

动态代理

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

public class Main {
    public static void main(String[] args) {
        PersonProxy personProxy = new PersonProxy(new XiaoMing());
        Person fundManager = personProxy.createProxy();
        fundManager.buy();
        fundManager.sell();
        fundManager.autoInvestment();
    }
}
interface Person{
    boolean buy();
    boolean sell();
    boolean autoInvestment();
}
class XiaoMing implements Person{
    @Override
    public boolean buy() {
        System.out.println("我是小明,我要买基金");
        return false;
    }
    @Override
    public boolean sell() {
        System.out.println("我是小明,我要出售基金");
        return false;
    }
    @Override
    public boolean autoInvestment() {
        System.out.println("我是小明,我要定投基金");
        return false;
    }
}
class PersonProxy implements InvocationHandler {
    Object target;
    PersonProxy(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        System.out.println("方法"+method.getName()+"已经被我代理");
        if("buy".equals(method.getName())){
            method.invoke(target, args);
            System.out.println("我是代理,我将帮你买基金");
        }
        return true;
    }
    public <T> T createProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

结果

方法buy已经被我代理
我是小明,我要买基金
我是代理,我将帮你买基金
方法sell已经被我代理
方法autoInvestment已经被我代理
  • target : 被代理的对象
  • InvocationHandler: jdk 动态代理类
  • invoke: 由jdk动态代理的方法,
    • proxy : jdk 代理类
    • method : 当前被代理类的方法
    • args 当前被代理类的方法参数
  • Proxy.newProxyInstance : 代理类的实例化方法
    • target.getClass().getClassLoader() : 目标类的 ClassLoader
    • target.getClass().getInterfaces() : 目标类的 interfaces
    • this : 代理类对象

动态代理-代理接口

想要实例化接口,但是又不创建实例类的骚操作,具体实现方法完全通过动态代理自由实现。

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

public class Main {

    public static void main(String[] args) {
        Person personProxy = PersonProxy.createProxy(Person.class);
        personProxy.say();
    }

}

interface Person{
    void say();
}

class PersonProxy implements InvocationHandler {
    Class target;
    PersonProxy(Class target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我就是"+method.getName()+"函数的方法体!");
        return null;
    }
    public static  <T> T createProxy(Class clazz){
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz}, new PersonProxy(clazz));
    }
}

结果

我就是say函数的方法体!

是不是非常 amazing !!!
根本没有任何的实例类!但是同样可以调用方法!可以调侃的说接口自己实现了自己

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java 静态代理和动态代理 的相关文章

随机推荐

  • 建立安全连接失败连接到 120.79.9.99:9200 时发生错误。SSL 接收到一个超出最大准许长度的记录。错误代码:SSL_ERROR_RX_RECORD_TOO_LONG

    建立安全连接失败 连接到 120 79 9 99 9200 时发生错误 SSL 接收到一个超出最大准许长度的记录 错误代码 SSL ERROR RX RECORD TOO LONG 因为我是用https访问的需要安全协议只要改为http就行
  • docker运行有数据库连接的springboot项目无法访问

    docker run name tsb p 8808 8080 d testspringboot 8808 8888 前一个数值是访问路径的端口号 后一个数值是上传的jar包中项目设定的端口号 默认8080 访问测试 测试地址 http 1
  • Spark学习笔记(二)

    以下笔记基于对尚硅谷spark教程的学习 Spark版本3 0 目录 什么是 RDD RDD核心属性 执行原理 基础编程 创建环境 RDD 创建 从集合中创建RDD 从文件中创建RDD RDD 转换算子 Value 类型 双Value类型
  • C1认证学习笔记(第一章)

    C1认证 一 计算机通识 进制转换 进制定义 进制之间的转换 任务训练练习 信息单位 单位定义 换算公式 任务训练练习 数据校验 任务背景 奇偶校验 任务训练练习 多媒体基础参数 任务背景 参数定义 计算公式 任务训练练习 HTTP 任务背
  • 【Transformer】12、Do Vision Transformers See Like Convolutional Neural Networks?

    文章目录 一 背景 二 方法 论文链接 https arxiv org pdf 2108 08810 pdf 出处 NeurIPS2021 一 背景 Transformer 现在在视觉方面取得了超越 CNN 的效果 所以作者就有一个问题 T
  • SQL server2019安装教程

    建议 建议给位看官先看完再动手 也可以多搜索其他的文章多看看 心里有数儿了再按照文档执行 有条件的在虚拟机里面跑一遍 下载必备 由于安装文件太大 所以没有办法上传 各位就请自行下载 我尝试着加一下链接SQL引导包的链接 也就是图片中的第二个
  • leetcode#26 Remove Duplicates from Sorted Array

    给定一个排序数组 你需要在原地删除重复出现的元素 使得每个元素只出现一次 返回移除后数组的新长度 不要使用额外的数组空间 你必须在原地修改输入数组并在使用 O 1 额外空间的条件下完成 示例 1 给定数组 nums 1 1 2 函数应该返回
  • JS 数组求和的5种方法(解题报告)

    转自牛客网 题目 题目描述 计算给定数组 arr 中所有元素的总和 输入描述 数组中的元素均为 Number 类型 输入例子 sum 1 2 3 4 输出例子 10 不考虑算法复杂度 用递归做 1 2 3 4 5 6
  • 推荐10个AI人工智能技术网站

    推荐 将 NSDT场景编辑器加入你的3D工具链 3D工具集 NSDT简石数字孪生 1 AI Trends AI Trends https www aitrends com 是一个专注于人工智能领域的网站 它提供了最新的AI技术和应用趋势的报
  • C++ 常用数学函数详解汇总#include<math.h>

    目录 前言 一 头文件 二 常用函数 1 开平方 2 求常数e的x次方 3 求常数x的y次方 4 求对数lnx lgx 5 求x绝对值 6 取整函数 7 产生随机数 8 取整与取余 9 三角函数 10 反三角函数 11 的表示 前言 在实际
  • 左神-11 动态规划(仔细看end)

    最长递增子序列 01背包问题 硬币找零问题 用空间换时间 1 2 3 4 5 6 end 转载于 https www cnblogs com h3953774 p 7307790 html
  • 卷麻了,00后测试用例写的比我还好,简直无地自容.....

    前言 作为一个测试新人 刚开始接触测试 对于怎么写测试用例很头疼 无法接触需求 只能根据站在用户的角度去做测试 但是这样情况会导致不能全方位的测试APP 这种情况就需要一份测试用例了 但是不会写 求指教 还有就是测试出来的bug该如何追踪
  • Prometheus Node_exporter 之 Node Exporter

    Node Exporter 1 Node Exporter Scrape Time type GraphUnit secondsLabel Seconds collector 各个收集器持续时间metrics node scrape col
  • 安全SaaS,在中国TO B中艰难成长

    无论是一体化 还是以业务为中心专攻政企或金融客户 还是针对中小微企业市场推出免费产品 都可能成为未来安全SaaS规模化的发展路径 作者 斗斗 编辑 皮爷 出品 产业家 5G 物联网 AI 云计算等技术的应用 让生产 服务过程加速数字化 云化
  • 【Qt】UI显示中文

    QT UI显示中文的三种方法 最近在用Qt做项目 遇到UI不能显示中文的问题 发现有3种方法可以解决 先记录一下 方法一 QString fromLocal8Bit 你好中国 1 方法二 QStringLiteral 你好中国 1 方法三
  • cmake 报错

    目录 错误 原因 错误 The C compiler identification is unknown The CXX compiler identification is unknown CMake Error at CMakeList
  • Android加载圆形(圆角)图片的方式总结(RoundedBitmapDrawable、Glide)

    一 问题引入 Android开发中经常要使用到ImageView 而ImageView控件自带的宽度width 高度height等属性无法让ImageView呈现出圆形 圆角这样的形状 相信很多小伙伴都和我一样为这个问题苦恼 现在介绍几种方
  • 2022如何做副业?35岁前,千万别让死工资绊住你赚钱的步伐

    近年来互联网行情下降 好多人都在思考要不要搞个副业来抵御风险 这不又来事了 这两天又爆了互联网大裁员 继阿里 向社会输送人才 之后 京东又搞了个 毕业礼 整的小伙伴们人心惶惶 副业的关注度又一波升级 那今天我们就来聊聊 程序员做副业这件事
  • 【计算机视觉

    文章目录 一 检测相关 11篇 1 1 BandRe Rethinking Band Pass Filters for Scale Wise Object Detection Evaluation 1 2 Morphological Ima
  • java 静态代理和动态代理

    什么是代理 从字面意思来说 代理就是代替处理的意思 从程序层面来说 代理就是代替某个程序 处理某个事情 静态代理 场景1 小明需要买基金 public class Main public static void main String ar