设计模式:代理模式

本文深入探讨了代理模式的概念,包括静态代理和动态代理两种形式。通过具体案例解释了代理模式如何帮助增强目标对象功能并提供保护,同时介绍了JDK动态代理和CGLib代理的实现原理及对比。

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

一、简介

    代理模式指的是客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。使用代理模式有两个目的:保护目标对象;增强目标对象。

    代理模式的结构:

  • 真实类:客户端要调用的对象的类型;
  • 接口:真实要执行的对象所实现的接口;
  • 代理类:实现了和真实所实现的相同接口,客户端通过调用代理类的实例间接调用真实类的对象。

二、静态代理

    用一个例子来表示代理模式:有个人renter要租房子,但是对当地不熟,需要一个当地的朋友friend来帮他找房子。

1、真实类的接口

    Person:

public interface Person {

    void findHouse();
}

2、真实类

    Renter:

public class Renter implements Person {
    @Override
    public void findHouse() {
        System.out.println("找房子");
    }
}

3、代理类

    Friend:

public class Friend {

    private Renter renter;

    public Friend(Renter renter) {
        this.renter = renter;
    }

    public void findHouse() {
        System.out.println("朋友代找房子");
        renter.findHouse();
        System.out.println("朋友找到房子");
    }
}

4、客户端应用

public class StaticProxyMain {

    public static void main(String[] args) {
        // 传入的参数renter,表示这个代理类只帮这个需要找房子的朋友找房子
        Friend friend = new Friend(new Renter());
        friend.findHouse();
    }
}

三、动态代理

    动态代理和静态代理的基本思想是一致的,只不过动态代理的功能更加强大,随着业务的扩展适应性更强。

    还是以上面的找房子为例,动态代理相当于找房子这个业务发展成了房屋中介,可以满足多样化的租房需求。

1、JDK动态代理

1.1 动态代理类

    动态代理的关键,就是实现JDK的InvocationHandler接口,并复写invoke方法,实现在invoke方法中调用传入的Object的相应方法。

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

public class Agency implements InvocationHandler {

    /**
     * 被代理的对象
     */
    private Object target;

    public Object getInstance(Object target) {
        this.target = target;
        Class<?> type = target.getClass();
        return Proxy.newProxyInstance(type.getClassLoader(), type.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object object = method.invoke(this.target, args);
        after();
        return object;
    }

    private void before() {
        System.out.println("中介开始找房");
    }

    private void after() {
        System.out.println("中介找房结束");
    }
}

1.2 应用

public class JdkProxyMain {

    public static void main(String[] args) {
        Person person = (Person) new Agency().getInstance(new Renter());
        person.findHouse();
    }
}

1.3 JDK实现动态代理的过程

    JDK动态代理生成代理对象的过程,叫做字节码重组:

  1. 通过反射,获取被代理对象的引用,并且获取它的所有接口;
  2. JDK动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口;
  3. 动态生成Java代码,新加的业务逻辑方法由一定的逻辑代码调用;
  4. 编译新生成的Java代码.class文件;
  5. 重新加载到JVM中运行。

    总的来说,原理分成两部分:

  1. 代理类的生成:直接编写Class字节码;
  2. 代理方法的调用:反射

2、CGLib代理

2.1 代理类

public class CglibAgency implements MethodInterceptor {

    public Object getInstance(Class<?> type) {
        Enhancer enhancer = new Enhancer();
        // 设置新类的父类
        enhancer.setSuperclass(type);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object obj = methodProxy.invokeSuper(o, objects);
        after();
        return obj;
    }

    private void before() {
        System.out.println("代理公司开始找房");
    }

    private void after() {
        System.out.println("代理公司找房结束");
    }
}

2.2 应用

public class CglibProxyMain {

    public static void main(String[] args) {
        Renter renter = (Renter) new CglibAgency().getInstance(Renter.class);
        renter.findHouse();
    }
}

2.3 原理

  • 代理类的编写:使用ASM框架编写Class字节码;
  • 代理方法的调用:FastClass机制,为代理类或被代理类各生成一个类,这个类会为代理类或被代理类的方法分配一个int类型的index。FastClass可以直接使用这个index定位要调用的方法,并直接进行调用,省去了反射的过程。

2.4 CGLib和JDK动态代理对比

  1. JDK动态代理实现了被代理对象的接口,CGLib代理继承了被代理对象;
  2. JDK动态代理直接写Class字节码,CGLib代理使用ASM框架写Class字节码,CGLib代理实现更复杂、效率更低;
  3. JDK动态代理调用代理方法是通过反射机制调用的,CGLib代理是通过FastClass机制直接调用的,CGLib代理的执行效率更高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值