Java设计模式之代理模式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、Java代理模式?

概念:Java代理模式(Proxy Pattern)是一种结构型设计模式,它允许为另一个对象提供一个代替或占位符对象以控制对它的访问。代理模式可以在不直接使用实际对象的情况下,提供对目标对象的访问。(为真实对象提供代理,然后供其他对象通过代理访问真实对象
代理形式有三种:分别是静态代理动态代理cglib动态代理
主要角色:

代理(Proxy)TeacherDaoProxy代理对象与目标对象TeacherDao有相同的接口,可以代替真实对象TeacherDao进行teach操作。
目标(Subject):需要被代理的真实对象TeacherDao
请求(Request):客户端通过代理对象发起的请求。
客户端(Client):使用代理对象TeacherDaoProxy的代码。

使用场景:

  1. 网络请求代理:为网络请求创建代理,可以在请求前后添加日志记录、错误处理、线程管理等。
  2. 图片加载代理:使用代理模式管理图片的加载和缓存,以及处理图片的异步加载和内存优化。
  3. 内存管理:对象的延迟初始化,例如,通过代理模式延迟加载大对象,以减少内存消耗。
  4. 权限检查代理:在执行需要特定权限的操作之前,使用代理进行权限检查和请求。
  5. 数据访问对象(DAO)代理:为数据库访问操作创建代理,以封装数据库操作和事务管理。

二、静态代理

在这里插入图片描述

步骤1.编写其接口

代码如下(示例):

/**
 * 静态代理——接口
 */
public interface ITeacherDao {
    void teach();//代理的方法
}

步骤2.编写目标对象

代码如下(示例):

/**
 * 目标对象(被代理的对象)——都要实现 ITeacherDao 接口
 */
public class TeacherDao implements ITeacherDao{
    @Override
    public void teach() {
        System.out.println("林大大在上课......");
    }
}

步骤3.编写代理对象

/**
 * 静态代理——代理对象
 */
public class TeacherDaoProxy implements ITeacherDao{

    private ITeacherDao target;//目标对象,通过这个对象要实现最终的调用

    //TODO 通过这个构造器,把目标对象作为参数代入,从而实现真正的代理实现
    public TeacherDaoProxy(ITeacherDao target) {
        this.target = target;
    }

    @Override
    public void teach() {
        System.out.println("开始代理......");//这里可以加入一些扩展功能逻辑
        target.teach();//目标对象的 teach()
        System.out.println("提交....");
    }
}

步骤4.编写Client

/**
 1. 静态代理——客户端测试类
 */
public class Client {
    public static void main(String[] args) {
        //1.创建目标对象(被代理的对象)
        TeacherDao teacherDao=new TeacherDao();
        //2.创建代理对象,同时将目标对象传递给代理对象
        TeacherDaoProxy teacherDaoProxy=new TeacherDaoProxy(teacherDao);
        //3.通过代理对象,调用到目标对象的 teach() 方法(即执行的是代理对象的方法,再由代理对象去调用目标对象的方法)可断点查看每一步的走向
        teacherDaoProxy.teach();
    }
}

注:teacherDaoProxy.teach()调用到目标对象的 teach() 方法(即执行的是代理对象的方法,再由代理对象去调用目标对象的方法)可断点查看每一步的走向
测试结果如下:
在这里插入图片描述

三、动态代理

在这里插入图片描述
注: 1. 代理对象不需要实现接口,但是目标对象要实现接口,否则不能使用动态代理
2. 动态代理也叫作:JDK代理接口代理

步骤1.编写其接口

代码如下(示例):

/**
 * 动态代理——接口
 */
public interface ITeacherDao {
    void teach();//代理的方法
}

步骤2.编写目标对象

代码如下(示例):

/**
 * 目标对象(被代理的对象)——都要实现 ITeacherDao 接口
 */
public class TeacherDao implements ITeacherDao{
    @Override
    public void teach() {
        System.out.println("林大大在上课......");
    }
}

步骤3.编写代理类

代码如下(示例):

/**
 * 动态代理——代理工厂
 */
public class ProxyFactory {
    private Object target;//目标对象,通过这个对象要实现最终的调用

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象生成一个代理对象
    public Object getProxyInstance(){
        /**
         * 类加载器:target.getClass().getClassLoader(),用于定义代理类的类加载器。
         * 接口数组:target.getClass().getInterfaces(),代理类需要实现的接口列表。这里使用了目标对象 target 实现的所有接口。
         * 一个实现了 InvocationHandler 接口的实例:这是一个自定义的调用处理器,负责定义代理对象的方法调用逻辑。
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("JDK代理开始了....");
                        Object result = method.invoke(target, args);
                        return result;
                    }
                });
    }
}

核心代码:

return Proxy.newProxyInstance(target.getClass().getClassLoader(),
        target.getClass().getInterfaces(),
        new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("JDK代理开始了....");
                Object result = method.invoke(target, args);
                return result;
            }
        });

类加载器:target.getClass().getClassLoader(),用于定义代理类的类加载器。
接口数组:target.getClass().getInterfaces(),代理类需要实现的接口列表。这里使用了目标对象 target 实现的所有接口。
一个实现了 InvocationHandler 接口的实例:这是一个自定义的调用处理器,负责定义代理对象的方法调用逻辑。

步骤4.编写Client

/**
 * 动态代理——客户端测试类
 */
public class Client {
    public static void main(String[] args) {
        //1.创建目标对象(被代理的对象)
        ITeacherDao target=new TeacherDao();
        //2.创建代理对象,同时将目标对象传递给代理对象,同时需要转成  ITeacherDao
        ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
        //3.通过代理对象,调用到目标对象的 teach() 方法(即执行的是代理对象的方法,再由代理对象去调用目标对象的方法)可断点查看每一步的走向
        System.out.println(proxyInstance.getClass());
        proxyInstance.teach();
    }
}

测试结果如下:
在这里插入图片描述

四、Cglib代理

从上面可以看出,jdk动态代理的前提条件是,要有接口存在,那还有许多场景是没有接口的,这个时候就需要cglib动态代理了,CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
 想具体实现该功能的可以看以下博客:
CGLIB详细讲解
深度思考】聊聊CGLIB动态代理原理

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值