代理模式 静态代理和动态代理(jdk、cglib)

一、代理模式

一个类代表另一个类去完成扩展功能,在主体类的基础上,新增一个代理类,扩展主体类功能,不影响主体,完成额外功能。比如买车票,可以去代理点买,不用去火车站,主要包括静态代理和动态代理两种模式。

代理类中包含了主体类

二、静态代理

无法根据业务扩展,每一次都要根据主体类,创建一个代理,如果多个主体类,就要多个代理。

创建一个接口

csharp 复制代码
public interface Image { void display(); }

创建实现接口的实体类。

typescript 复制代码
public class RealImage implements Image {

    private String fileName;

    public RealImage(String fileName){

        this.fileName = fileName;

        loadFromDisk(fileName);

    }

    @Override

    public void display() {

        System.out.println("Displaying " + fileName);

    }

    private void loadFromDisk(String fileName){

        System.out.println("Loading " + fileName);

    }

}

代理类

typescript 复制代码
public class ProxyImage implements Image{

    private RealImage realImage;

    private String fileName;

    public ProxyImage(String fileName){

        this.fileName = fileName;

    }

    @Override

    public void display() {

        if(realImage == null){

            realImage = new RealImage(fileName);

        }

        realImage.display();

    }

}

当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

arduino 复制代码
public class ProxyPatternDemo {

    public static void main(String[] args) {

        Image image = new ProxyImage("test_10mb.jpg");

        // 图像将从磁盘加载

        image.display();

        System.out.println("");

        // 图像不需要从磁盘加载

        image.display();

    }

}

缺点:ProxyImage 代理类已经固定是RealImage的类的代理了,所以不能在扩展了

三、动态代理

解决静态代理问题,代理类不是固定为某个主体类服务。Spring 的AOP底层就是动态代理实现

1)jdk代理

底层利用反射,实现 InvokeHandler,生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,动态生成代理对象

kotlin 复制代码
public class JDKProcyImage implements InvocationHandler {

    private Object object;

    public JDKProcyImage(Object o) {

        this.object  = o;

    }

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (method.getName().equals("display")){

            System.out.println("我是Image的代理,我跟realImage展示图片");

            method.invoke(object,args);

            System.out.println("我是Image的代理,我说完了");

        }

        return null;

    }

}

调用:

arduino 复制代码
public class JDKProcyImageDemo {

    public static void main(String[] args) {

        JDKProcyImage imageProxy = new JDKProcyImage(new RealImage2());

        // 图像将从磁盘加载

        Image image = (Image) Proxy.newProxyInstance(JDKProcyImageDemo.class.getClassLoader(), new Class[]{Image.class}, imageProxy);

        image.display();

    }

}

2)cglib动态代理

利用asm开源包,是对JDK代理的一个加强,实现MethodInterceptor类

typescript 复制代码
public class CglibProxyImage implements MethodInterceptor {

    private Object object;

    public CglibProxyImage(Object o) {
        this.object  = o;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (method.getName().equals("display")){
            System.out.println("我是Image的代理,我跟realImage展示图片");
            method.invoke(object,objects);
            System.out.println("我是Image的代理,我说完了");
        }
        return null;
    }
}
public class CglibProxyImageDemo {


    public static void main(String[] args) {
        CglibProxyImage imageProxy = new CglibProxyImage(new RealImage3());
// 调用方便
        RealImage3 realImage3 = (RealImage3) Enhancer.create(RealImage3.class, imageProxy);
        realImage3.display();


    }
}

四、总结

jdk与cglib比较

(1)JDK动态代理,java本身,只能对实现了接口的类生成代理,而不能针对类,主体类需要实现接口,调用操作繁琐

(2)CGLIB,依赖第三包是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,无需实现接口,调用简单。目标对象不用实现接口,底层通过继承目标对象产生代理对象。

相关推荐
ChinaRainbowSea8 分钟前
9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明
java·javascript·分布式·后端·rabbitmq·ruby·java-rabbitmq
掉毛的小羊羔14 分钟前
🛸理解 MCP:工作原理、技术架构与 AI Agent 的关系全解析
前端·后端·架构
写bug写bug15 分钟前
掌握 HTTP 状态码
前端·后端·http
写bug写bug35 分钟前
图解六种常见负载均衡算法,一看就懂!
java·后端·负载均衡
阿里云云原生41 分钟前
Python3 AI 通义灵码 VSCode插件安装与功能详解
后端·python·visual studio code
瀚海澜生43 分钟前
理解 Go 语言 panic 机制:错误类型、崩溃场景及修复
后端·面试
码农周1 小时前
springboot Filter实现请求响应全链路拦截!完整日志监控方案
java·spring boot·后端
努力的搬砖人.1 小时前
nginx如何实现负载均衡?
java·经验分享·后端·nginx
东方雴翾1 小时前
CSS语言的游戏AI
开发语言·后端·golang
uhakadotcom2 小时前
了解 psycopg2 连接池
后端·面试·github