代理

代理

静态代理

代理模式给某一个对象提供一个代理对象,并由代理对象控制原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

目的:

  1. 同过引入代理对象的方式来间接访问对象,防止直接问对象给系统带来不必要的复杂性。

  2. 通过代理对象对访问进行控制。

    代理应用场景

代理模式一般会有三个角色

抽象角色: 指代理角色和真实角色对外提供的公共接口,一般为一个接口。

真实角色: 需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真真的业务逻辑在此。

代理角色: 需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作,将统一的流程控制都放在代理角色中处理。

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象需要一起实现相同的接口或者是继承相同父类。一般来说,被代理对象和代理对象是一对一的关系,当然一个代理对象对应多个被代理对象也是可以的。

静态代理,一对一则会出现静态代理对象量多、代码量大、从而导致代码复杂,可维护性差的问题,一对多则代理对象会出现扩展能力差的问题。

java 复制代码
//公共接口
public interface Message {
    void message();
}
​
//被代理类
public class Zhangsan implements Message {
    @Override
    public void message() {
        System.out.println("大家好我是Zhangsan");
    }
}
​
//代理类
public class Agent implements Message {
    private Message message;
​
    public Agent(Message message) {
        this.message = message;
    }
​
    @Override
    public void message() {
        message.message();
    }
}
​
public static void main(String[] args) throws Exception {
        //静态代理
        final Zhangsan zhangsan = new Zhangsan();
        final Agent agent = new Agent(zhangsan);
        agent.message();
}

动态代理

在运行时再创建代理类和其实例,因此显然效率更低。要完成这个场景,需要在运行期间动态创建一个Class. JDK提供了Proxy类来完成这件事情。

java 复制代码
 public static void main(String[] args) throws Exception {
        final Zhangsan zhangsan = new Zhangsan();
​
        //动态代理
        Object proxy = Proxy.newProxyInstance(MyClass.class.getClassLoader(),
                new Class[]{Message.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy,
                                         Method method,
                                         Object[] args) throws  Throwable {
                        // TODO: 2023/11/10  此处会造成栈内存的内存泄漏
                        //System.out.println(proxy);
                        return method.invoke(zhangsan,args);
                    }
                });
        ((Message)proxy).message();
        final MyClass myClass = new MyClass();
    }
​
​

实际上,Proxy.newProxyInstance会创建一个Class,与静态代理不同,这个Class不是具体的.java源文件编译而来的,既没有真真的文件,只是在内存中按照Class的格式生成一个Class。

备注:需要使用jdk1.8才会有sun.misc.ProxyGenerator

arduino 复制代码
   private static void buildProxyClass() throws Exception{
        String proxyName = Message.class.getName()+ "$Proxy0";
        final byte[] bytes = ProxyGenerator.generateProxyClass(proxyName,
                                                               new Class[]{Message.class});
        final FileOutputStream fileOutputStream = 
                                        new FileOutputStream("lib/" + proxyName + ".class");
        fileOutputStream.write(bytes);
        fileOutputStream.close();
    }

然后可以在生成的文件中查看我们的代理类:

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
​
package com.example.lib;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
​
public final class Message$Proxy0 extends Proxy implements Message {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;
​
    public Message$Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
​
    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
​
  //而这个代理类中所有的方法的实现
    public final void message() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
​
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
​
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
​
  //在初始化的时候,获得method备用
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.example.lib.Message").getMethod("message");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

这里的h其实就是InvocationHandler接口,所以我们在使用动态代理时,传递InvocationHandler就是一个监听,在代理对象上执行方法,都会有这个监听回调出来

相关推荐
Rain的Java大神之路31 分钟前
线上接口负载满了如何解决
java·数据库·redis·后端·缓存·面试·架构
counting money1 小时前
Tomcat 专题:从基础架构到性能调优与 WebSocket 实战
java·websocket·tomcat
xiaohaiAIgeo2 小时前
【2026年】HG/T 20656-2024化工暖通空调设计规范:新版标准的变化与影响
java·前端·javascript·科普知识
小强库计算机毕业设计2 小时前
基于 Spring Boot + Vue3 的校园管理系统
java·spring boot·后端·项目实战·管理系统·技术分享·校园管理系统实战
霸道流氓气质2 小时前
Java中信号量(Semaphore):从本地到分布式
java·开发语言·分布式
怪奇云呼军2 小时前
G.711、Opus 和重采样会拖慢识别吗?闪电智能VoiceAgent 的音频入口怎么选
java·人工智能·python·算法·云计算·音视频
编程令我快乐2 小时前
maven部分构建参数讲解
java·maven
ZC跨境爬虫2 小时前
LeetCode 27. 移除元素(双指针详解 + Java Python 多解法对比)
java·python·leetcode
kisbad3 小时前
Day 036|OpenAI Agents SDK 快速开始:今天跑通第一个 Agent
java·前端·javascript
憧憬成为java架构高手的小白3 小时前
langchain4j框架学习
java