代理模式 静态代理和动态代理(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,依赖第三包是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,无需实现接口,调用简单。目标对象不用实现接口,底层通过继承目标对象产生代理对象。

相关推荐
正在走向自律3 分钟前
时序数据管理:金仓数据库破局之道
java·后端·struts·时序数据库·金仓kes v9
moxiaoran57539 分钟前
springboot多模块项目构建docker镜像
spring boot·后端·docker
小北方城市网12 分钟前
SpringBoot 集成消息队列实战(RabbitMQ/Kafka):异步通信与解耦,落地高可靠消息传递
java·spring boot·后端·python·kafka·rabbitmq·java-rabbitmq
JaguarJack17 分钟前
PHP 8.5 闭包和一等可调用对象进入常量表达式
后端·php·服务端
冷冷的菜哥21 分钟前
go(golang)调用ffmpeg对视频进行截图、截取、增加水印
后端·golang·ffmpeg·go·音视频·水印截取截图
短剑重铸之日23 分钟前
《7天学会Redis》特别篇:Redis十大经典面试题2
数据库·redis·后端·缓存·架构
草莓熊Lotso29 分钟前
Qt 控件核心入门:从基础认知到核心属性实战(含资源管理)
运维·开发语言·c++·人工智能·后端·qt·架构
赴前尘10 小时前
golang 查看指定版本库所依赖库的版本
开发语言·后端·golang
Marktowin16 小时前
Mybatis-Plus更新操作时的一个坑
java·后端