设计模式之----代理模式Proxy

本文深入解析了代理模式的概念、分类及应用场景,包括静态代理、JDK动态代理和Cglib动态代理的特点与代码实现,对比了各种代理模式的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.代理模式简介:

1)概念:为对象提供一个替身,以控制对这个象的访 问。 即通过代理 对象 访问目标.这样做的 好处是 :可以在目标对象实现的基础上 ,增强额外的 功能操作 ,即扩展目标对象的功能。
2) 被代理的对象可以是远程对象 、创建开销大的对象或需要安全控制 的对象
3) 分类:代理模式 有不同的形式 , 主要有三种 静态代理 、动态代理 (JDK (JDK代 理、接口理)和 Cglib Cglib 代理 (可以在内存动态的创建对象, 而不需要实现接口他是属于 动态代理的范畴 )。

二、静态代理

1.简介:静态代理在使用时 ,需要定义接口或者父类 ,被代理对象(即目标对象 )与代理对象一 起实现相同的接口或者是继承父类

在这里插入图片描述
2.静态代理优 缺点

  1. 优点:在 不修改目标对象的功能前提下 , 能通过代理对象目标功能扩展
  2. 缺点:因 为代理对象需要与目标实现一样的接口 ,所以会有很多代理 类;一旦接口增加方法 ,目标对象与代理象都要维护
    3.代码举例:
public interface Player {
    //玩游戏的方法
    public  void paly();
}
//普通玩家类:
public class CommonPlayer implements Player{

    public void paly() {
        System.out.println("该游戏账号正在使用,游戏中。。。");
    }
}
//代理类:
public class ProxyPlayer implements Player {
    //代练玩家其实也是个普通玩家
    private CommonPlayer commonPlayer;

    public ProxyPlayer(CommonPlayer commonPlayer) {
        this.commonPlayer = commonPlayer;
    }

    public void before(){
        System.out.println("接受委托,开始代练账号。。。");
    }
    public void after(){
        System.out.println("完成任务。。。");
    }
    public void paly() {
        before();
        commonPlayer.paly();
        after();
    }
}
public class Client {

    public static void main(String[] args) {
         CommonPlayer commonPlayer = new CommonPlayer();
         ProxyPlayer proxyPlayer = new ProxyPlayer(commonPlayer);
         proxyPlayer.paly();
    }
}

执行结果:
在这里插入图片描述

三、jdk动态代理
1.jdk动态代理模式的基本介绍

  1. 代理对象 ,不需要实现接 口, 但是目标对 象要 实现接 口,否则不能用动态代理
  2. 代理对象的生成,是利用 JDK 的API ,动态的在内存中构建代理对 象
    3)JDK 动态代理也叫 做:JDK 代理、接口代理
    2.jdkProxy代码:
package JdkProxy;

public interface Producer{
    void sale(Float price);//销售
    String order(Integer id);//下订单
}

package JdkProxy;

import java.util.UUID;

public class MyProducer implements Producer {
    public  void sale(Float price) {
        System.out.println("卖出商品,价格是:"+price*0.95);
    }

    public String order(Integer  id) {
        return  UUID.randomUUID().toString()+id;
    }

}
package JdkProxy;

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

public class ProducerProxy implements InvocationHandler {
    private Object target = null;

    public ProducerProxy(Object obj) {
        this.target = obj;
    }


    public Object getProxyInstance(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this
        );
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //获取方法的参数
        Object arg =  args[0];
        Object res = null;
        if("sale".equals(method.getName())){
            res =  method.invoke(this.target,arg);
        }else if("order".equals(method.getName())){
            res = method.invoke(this.target,arg);
        }
        return  res;
    }

    public static void main(String[] args) {
        MyProducer myProducer = new MyProducer();
        ProducerProxy producerProxy = new ProducerProxy(myProducer);
        Producer myProxy = (Producer) producerProxy.getProxyInstance();
        String orderId = myProxy.order(9999);
        System.out.println(orderId);
        myProxy.sale(1000.0f);
    }
}

三、Cglib 代理
1.Cglib 代理基本介绍:

  1. 静态代 理和 JDK 代理模式 都要 求目标对象是实现一个接口,但是有时候目标对象只 是一个单独的对象 ,并没有实现任何的接口 ,这个时候可使用目标对象子类来实现代理这就是 Cglib代理
  2. Cglib 代理也 叫作子类代理 ,它是在内存中构建一个子类对象从而实现目标功 能扩展 , 有些 书也将 Cglib 代理 归属到动态。
  3. Cglib 是一个强大的高性能代码生成包 ,它可以在运行期扩展 java类与实现 java接 口.它广泛的被许多 AOP 的框架使用 ,例如 Spring AOP ,实现 方法拦截
  4. 在AOP 编程 中如何选择代理模式:
    a. 目标对 象需要实 现接 口,用JDK 代理
    b. 目标对 象不需要实 现接 口,用Cglib代理
  5. Cglib Cglib包的底层是通过使用字节码处理框架 ASM 来

2.cglib Proxy代码:

package cglibProxy;

import java.util.UUID;

public class Producer {
    public  void sale(Float price) {
        System.out.println("卖出商品,价格是:"+price*0.95);
    }

    public String order(Integer  id) {
        return  UUID.randomUUID().toString()+id;
    }
}
package cglibProxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    private  Object target = null;

    public CglibProxy(Object target) {
        this.target = target;
    }
    public Object getProxyInstance() {
        //1. 创建一个工具类
        Enhancer enhancer = new Enhancer();
        //2. 设置父类
        enhancer.setSuperclass(target.getClass());
        //3. 设置回调函数
        enhancer.setCallback(this);
        //4. 创建子类对象,即代理对象
        return enhancer.create();
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object arg =  objects[0];
        Object res = null;
        if("sale".equals(method.getName())){
            res =  method.invoke(target,arg);
        }else if("order".equals(method.getName())){
            res = method.invoke(target,arg);
        }
        return  res;
    }

    public static void main(String[] args) {
        Producer producer = new Producer();
        CglibProxy cglibProxy = new CglibProxy(producer);
        Producer producerProxy = (Producer) cglibProxy.getProxyInstance();
        String id = producerProxy.order(1111);
        System.out.println(id);
        producerProxy.sale(2000.0f);
    }
}

四、常见面试题
1.JDK动态代理个CgLib动态代理的区别?
(1)要求不同:JDK动态代理只能代理实现了接口的类,没有实现接口的类不能实现JDK的动态代理;
而Cglib动态代理是针对类实现代理的,如果被代理类被final关键字所修饰,那么抱歉会失败
(2)底层:JDK 是通过 Java的反射机制实现的,Cglib 是通过ASM字节码框架实现的
(3)效率:
1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在jdk6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
2)但是在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,总之,每一次jdk版本升级,jdk代理效率都得到提升,而CGLIB代理消息确有点跟不上步伐。
3)jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适合单例模式。另外由于CGLIB的大部分类是直接对Java字节码进行操作,这样生成的类会在Java的永久堆中。如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。spring默认使用jdk动态代理,如果类没有接口,则使用cglib。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值