java 设计模式之代理模式

简介

代理模式:使用代理类来增强目标类的功能。在代码结构上,代理对象持有目标对象,通过代理对象访问目标对象,这样可以在不改变目标对象的前提下增加额外的功能,如权限校验、缓存等

代理模式内部的角色:

  • 目标类:实现业务功能
  • 代理类:用户通过代理类来访问目标类
  • 增强方法:代理类中要调用的方法,就是通过它来为目标类添加功能
  • 目标接口:代理类和目标类都需要实现目标接口,在有些情况下目标接口是不需要的

代理模式的分类:依据代理类的创建方式,代理模式分为静态代理和动态代理

spring、mybatis等常见框架中大量使用到了动态代理,例如spring的aop,通过动态代理来为目标类增加功能

代理模式的分类

静态代理

静态代理:用户手动编写代理类,在编译时,目标类、代理类已经全部确定

案例:目标类实现售卖功能,代理类中收取服务费

第一步:目标接口

java 复制代码
public interface SellTickets {
    void sell();
}

第二步:目标类

java 复制代码
public class TrainStation implements SellTickets {
    @Override
    public void sell() {
        System.out.println("火车站卖票");
    }
}

第三步:代理类

java 复制代码
public class ProxyPoint implements SellTickets {
    private final TrainStation trainStation;   // 代理类持有目标类的实例

    public ProxyPoint() { }

    public ProxyPoint(TrainStation trainStation) {
        this.trainStation = trainStation;
    }

    @Override
    public void sell() {
        System.out.println("代理点收取服务费");
        trainStation.sell();
    }
}

测试:

java 复制代码
public class StaticProxyClient {
    public static void main(String[] args) {
        // 创建代理类时,传入目标类的实例,通过代理类来访问目标类
        ProxyPoint proxyPoint = new ProxyPoint(new TrainStation());
        proxyPoint.sell();
    }
}

动态代理

动态代理:在程序运行时,基于字节码技术,动态地创建代理类。和静态代理不同的地方在于,静态代理时代理类需要用户手动编写,是编译时生成,动态代理时代理类由程序来自动创建,是运行时生成,用户只需要指定代理类要执行的增强方法和目标类。

用户可以使用jdk原生的方式来创建动态代理类,也可以使用第三方库,例如cglib,提供的方式来创建代理类

基于jdk的动态代理技术

jdk原生的动态代理技术

案例:

第一步:目标接口、目标类,和之前一样

第二步:创建代理类的工厂。代理类是运行时创建的,这里指定代理类的创建方式,程序运行时,使用用户指定的方式,在内存中动态地创建一个类,就是动态代理

java 复制代码
public class JdkProxyFactory {
    // 创建火车站的代理类
    public static Object getTrainStationProxyObj(TrainStation trainStation) {
        return dynamicProxy(trainStation,
                // 代理类中要执行的方法
                (InvocationHandler) (proxy, method, args) -> {  
                    // 这里代理类只拦截指定方法
                    if (method.getName().equals("sell")) {  
                        System.out.println("收取代理费");
                    }
                    return method.invoke(trainStation, args);  // 执行目标类中的方法
                });
    }

    // 传入目标对象和调用处理器
    private static <T> Object dynamicProxy(T target, InvocationHandler h) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader()  // 代理类的类加载器
                , target.getClass().getInterfaces()   // 代理类要实现的接口
                , h);
    }
}

测试:

java 复制代码
public class JdkProxyClient {
    public static void main(String[] args) {
        TrainStation targetObj = new TrainStation();
        SellTickets proxyObj = (SellTickets) JdkProxyFactory.getTrainStationProxyObj(targetObj);
        proxyObj.sell();
    }
}

基于cglib的动态代理技术

基于cglib的动态代理技术:由于jdk提供的动态代理技术要求目标类必须要实现目标接口,所以它的使用范围比较小,cglib提供了一种动态代理技术,它是基于继承关系,目标类不需要实现接口。

案例:

第一步:添加依赖

xml 复制代码
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

第二步:目标类,可以没有目标接口,因为cglib提供的动态代理技术,是基于继承关系来进行代理

第三步:创建代理类的工厂

java 复制代码
public class CgProxyFactory {
    public static TrainStation getProxyObj(TrainStation trainStation) {
        Enhancer enhancer = new Enhancer();
        // 代理类的父类
        enhancer.setSuperclass(TrainStation.class);
        // 代理类中要执行的方法
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method
                    , Object[] objects, MethodProxy methodProxy)
                    throws Throwable {
                if (method.getName().equals("sell")) {
                    System.out.println("收取代理费");
                }
                return method.invoke(trainStation, objects);
            }
        });
        return (TrainStation) enhancer.create();
    }
}

测试:

java 复制代码
public class CgProxyClient {
    public static void main(String[] args) {
        TrainStation targetObj = new TrainStation();
        TrainStation proxyObj = CgProxyFactory.getProxyObj(targetObj);
        proxyObj.sell();
    }
}

原理解析

查看创建出的代理类

使用arthas,查看动态创建出的代理类。具体方法,在程序中打印出代理类的类名,然后程序休眠,使用arthas连接程序,在arthas中使用jad查看类的字节码

案例:

java 复制代码
public class CgProxyClient {
    public static void main(String[] args) {
        TrainStation targetObj = new TrainStation();
        TrainStation proxyObj = CgProxyFactory.getProxyObj(targetObj);
        proxyObj.sell();

        // 代理类的类名
        // class org.wyj.proxy.cg_proxy.TrainStation$$EnhancerByCGLIB$$37abd3d3
        System.out.println("proxyObj.getClass() = " + proxyObj.getClass());

        // 程序休眠,方便arthus连接
        try {
            Thread.sleep(10 * 1000 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

使用arthas连接到当前程序,执行命令,jad ${类的全限定名},查看动态生成的代理类

jdk生成的代理类

案例:这里直接展示创建结果,下面就是之前案例中jdk在内存中动态创建的代理类的字节码,

java 复制代码
package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.wyj.proxy.jdk_proxy.SellTickets;

public final class $Proxy0
extends Proxy
implements SellTickets {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    // 构造方法,调用这个方法来创建代理类的实例
    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("org.wyj.proxy.jdk_proxy.SellTickets").getMethod("show", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("org.wyj.proxy.jdk_proxy.SellTickets").getMethod("sell", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        }
        catch (NoSuchMethodException noSuchMethodException) {
            throw new NoSuchMethodError(noSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException classNotFoundException) {
            throw new NoClassDefFoundError(classNotFoundException.getMessage());
        }
    }

    public final boolean equals(Object object) {
        try {
            return (Boolean)this.h.invoke(this, m1, new Object[]{object});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString() {
        try {
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode() {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void sell() {
        try {
            this.h.invoke(this, m3, null);
            return;
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

总结:使用jdk创建出的代理类,默认是Proxy的子类,并且实现了用户指定的接口

cglib创建的代理类

案例:之前案例中创建出的代理类

java 复制代码
package org.wyj.proxy.cg_proxy;

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.wyj.proxy.cg_proxy.TrainStation;

public class TrainStation$$EnhancerByCGLIB$$c8c06447
extends TrainStation
implements Factory {
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static final Method CGLIB$sell$0$Method;
    private static final MethodProxy CGLIB$sell$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$finalize$1$Method;
    private static final MethodProxy CGLIB$finalize$1$Proxy;
    private static final Method CGLIB$equals$2$Method;
    private static final MethodProxy CGLIB$equals$2$Proxy;
    private static final Method CGLIB$toString$3$Method;
    private static final MethodProxy CGLIB$toString$3$Proxy;
    private static final Method CGLIB$hashCode$4$Method;
    private static final MethodProxy CGLIB$hashCode$4$Proxy;
    private static final Method CGLIB$clone$5$Method;
    private static final MethodProxy CGLIB$clone$5$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class<?> clazz = Class.forName("org.wyj.proxy.cg_proxy.TrainStation$$EnhancerByCGLIB$$c8c06447");
        Class<?> clazz2 = Class.forName("java.lang.Object");
        Method[] methodArray = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, clazz2.getDeclaredMethods());
        CGLIB$finalize$1$Method = methodArray[0];
        CGLIB$finalize$1$Proxy = MethodProxy.create(clazz2, clazz, "()V", "finalize", "CGLIB$finalize$1");
        CGLIB$equals$2$Method = methodArray[1];
        CGLIB$equals$2$Proxy = MethodProxy.create(clazz2, clazz, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
        CGLIB$toString$3$Method = methodArray[2];
        CGLIB$toString$3$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        CGLIB$hashCode$4$Method = methodArray[3];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(clazz2, clazz, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = methodArray[4];
        CGLIB$clone$5$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
        clazz2 = Class.forName("org.wyj.proxy.cg_proxy.TrainStation");
        CGLIB$sell$0$Method = ReflectUtils.findMethods(new String[]{"sell", "()V"}, clazz2.getDeclaredMethods())[0];
        CGLIB$sell$0$Proxy = MethodProxy.create(clazz2, clazz, "()V", "sell", "CGLIB$sell$0");
    }

    final void CGLIB$sell$0() {
        super.sell();
    }

    // 重写目标类中的方法,在方法中调用用户设置的拦截器
    public final void sell() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object = methodInterceptor.intercept(this, CGLIB$sell$0$Method, CGLIB$emptyArgs, CGLIB$sell$0$Proxy);
            return;
        }
        super.sell();
    }

    final void CGLIB$finalize$1() throws Throwable {
        super.finalize();
    }

    // 重写Object类中的方法
    protected final void finalize() throws Throwable {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object = methodInterceptor.intercept(this, CGLIB$finalize$1$Method, CGLIB$emptyArgs, CGLIB$finalize$1$Proxy);
            return;
        }
        super.finalize();
    }

    final boolean CGLIB$equals$2(Object object) {
        return super.equals(object);
    }

    public final boolean equals(Object object) {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object2 = methodInterceptor.intercept(this, CGLIB$equals$2$Method, new Object[]{object}, CGLIB$equals$2$Proxy);
            return object2 == null ? false : (Boolean)object2;
        }
        return super.equals(object);
    }

    final String CGLIB$toString$3() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            return (String)methodInterceptor.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy);
        }
        return super.toString();
    }

    final int CGLIB$hashCode$4() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object = methodInterceptor.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
            return object == null ? 0 : ((Number)object).intValue();
        }
        return super.hashCode();
    }

    final Object CGLIB$clone$5() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            return methodInterceptor.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy);
        }
        return super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature signature) {
        String string = ((Object)signature).toString();
        switch (string.hashCode()) {
            case -1574182249: {
                if (!string.equals("finalize()V")) break;
                return CGLIB$finalize$1$Proxy;
            }
            case -508378822: {
                if (!string.equals("clone()Ljava/lang/Object;")) break;
                return CGLIB$clone$5$Proxy;
            }
            case 1826985398: {
                if (!string.equals("equals(Ljava/lang/Object;)Z")) break;
                return CGLIB$equals$2$Proxy;
            }
            case 1913648695: {
                if (!string.equals("toString()Ljava/lang/String;")) break;
                return CGLIB$toString$3$Proxy;
            }
            case 1978249955: {
                if (!string.equals("sell()V")) break;
                return CGLIB$sell$0$Proxy;
            }
            case 1984935277: {
                if (!string.equals("hashCode()I")) break;
                return CGLIB$hashCode$4$Proxy;
            }
        }
        return null;
    }

    public TrainStation$$EnhancerByCGLIB$$c8c06447() {
        TrainStation$$EnhancerByCGLIB$$c8c06447 trainStation$$EnhancerByCGLIB$$c8c06447 = this;
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(trainStation$$EnhancerByCGLIB$$c8c06447);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] callbackArray) {
        CGLIB$THREAD_CALLBACKS.set(callbackArray);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callbackArray) {
        CGLIB$STATIC_CALLBACKS = callbackArray;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object object) {
        block2: {
            Object object2;
            block3: {
                TrainStation$$EnhancerByCGLIB$$c8c06447 trainStation$$EnhancerByCGLIB$$c8c06447 = (TrainStation$$EnhancerByCGLIB$$c8c06447)object;
                if (trainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BOUND) break block2;
                trainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BOUND = true;
                object2 = CGLIB$THREAD_CALLBACKS.get();
                if (object2 != null) break block3;
                object2 = CGLIB$STATIC_CALLBACKS;
                if (CGLIB$STATIC_CALLBACKS == null) break block2;
            }
            trainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])object2)[0];
        }
    }

    public Object newInstance(Callback[] callbackArray) {
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
        TrainStation$$EnhancerByCGLIB$$c8c06447 trainStation$$EnhancerByCGLIB$$c8c06447 = new TrainStation$$EnhancerByCGLIB$$c8c06447();
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$SET_THREAD_CALLBACKS(null);
        return trainStation$$EnhancerByCGLIB$$c8c06447;
    }

    public Object newInstance(Callback callback) {
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$SET_THREAD_CALLBACKS(new Callback[]{callback});
        TrainStation$$EnhancerByCGLIB$$c8c06447 trainStation$$EnhancerByCGLIB$$c8c06447 = new TrainStation$$EnhancerByCGLIB$$c8c06447();
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$SET_THREAD_CALLBACKS(null);
        return trainStation$$EnhancerByCGLIB$$c8c06447;
    }

    public Object newInstance(Class[] classArray, Object[] objectArray, Callback[] callbackArray) {
        TrainStation$$EnhancerByCGLIB$$c8c06447 trainStation$$EnhancerByCGLIB$$c8c06447;
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
        Class[] classArray2 = classArray;
        switch (classArray.length) {
            case 0: {
                trainStation$$EnhancerByCGLIB$$c8c06447 = new TrainStation$$EnhancerByCGLIB$$c8c06447();
                break;
            }
            default: {
                throw new IllegalArgumentException("Constructor not found");
            }
        }
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$SET_THREAD_CALLBACKS(null);
        return trainStation$$EnhancerByCGLIB$$c8c06447;
    }

    public Callback getCallback(int n) {
        MethodInterceptor methodInterceptor;
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(this);
        switch (n) {
            case 0: {
                methodInterceptor = this.CGLIB$CALLBACK_0;
                break;
            }
            default: {
                methodInterceptor = null;
            }
        }
        return methodInterceptor;
    }

    public void setCallback(int n, Callback callback) {
        switch (n) {
            case 0: {
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
                break;
            }
        }
    }

    public Callback[] getCallbacks() {
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$BIND_CALLBACKS(this);
        TrainStation$$EnhancerByCGLIB$$c8c06447 trainStation$$EnhancerByCGLIB$$c8c06447 = this;
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] callbackArray) {
        Callback[] callbackArray2 = callbackArray;
        TrainStation$$EnhancerByCGLIB$$c8c06447 trainStation$$EnhancerByCGLIB$$c8c06447 = this;
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)callbackArray[0];
    }

    static {
        TrainStation$$EnhancerByCGLIB$$c8c06447.CGLIB$STATICHOOK1();
    }
}

总结:代理类是目标类的子类,会重写它从父类中继承来的方法,包括Object类中的方法。在重写的方法中,调用拦截器来完成任务,拦截器是用户提供的,指定了增强方法和目标对象的执行方式。

代理类失效的情况

基于jdk创建的代理类,代理类只可以代理目标接口中的方法,因为代理类只会实现目标接口中的方法。

基于cglib创建的代理类,代理类只可以代理目标类中可以被继承的方法,因为代理类只会重写可以被继承的方法,如果方法无法被继承,在执行时,会直接调用目标类中的方法,从而导致代理类无法代理。

代理类的执行效率

测试方式:执行100万次,每一次都创建一个代理类,然后调用一次代理类中的方法,方法中什么都不做,这里只关心方法的调用速度

java 复制代码
public class JdkProxyClient {
    public static void main(String[] args) {
        TrainStation targetObj = new TrainStation();

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            SellTickets proxyObj = (SellTickets) JdkProxyFactory.getTrainStationProxyObj(targetObj);
            proxyObj.sell();
        }
        long executeTime = System.currentTimeMillis() - startTime;
        System.out.println("执行时间:" + executeTime + "ms");
    }
}

得出的结论:

测试方式 基于jdk创建的代理类 基于cglib创建的代理类
创建100万个代理类,每个代理类都执行一次 112ms 1130ms
创建1个代理类,每个代理类都执行100万次 29ms 34ms

可以看出,执行速度差不多,但是jdk创建代理类的速度更快,因为jdk生成的字节码更少

源码解析

jdk创建代理的方式

API总结:

Proxy:public class Proxy implements java.io.Serializable:创建代理类的工具类,提供了静态方法,用于创建动态代理类和动态代理对象,它也是所有动态代理类的父类。

java 复制代码
public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;

    // 构造器的参数,动态生成的代理类,会生成一个构造方法,这里就是构造方法的参数
    /** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };
  
    // 创建代理类并且获取代理对象的方法,用户需要提供三个参数,用于加载代理类的类加载器、
    // 代理类需要实现的接口、代理类中需要执行的增强方法。
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        // 在这一步会生成代理类
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            // 获取代理类中指定的构造方法
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }
}

InvocationHandler:public interface InvocationHandler:调用处理器,在调用处理器中调用增强方法和目标对象。每个代理实例有一个相关联的调用处理器,代理对象内部实际上是通过调用处理器来工作的

java 复制代码
public interface InvocationHandler {

    // 参数proxy是代理对象
    // 参数method是目标类中的方法的Method对象,调用哪个方法,这儿就是哪个方法的实例
    // 参数args是method方法的参数
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

这里对源码的介绍很浅,重点是要理解创建代理类需要提供哪些参数、代理类的执行机制。

相关推荐
诺亚凹凸曼9 分钟前
Java基础系列-LinkedList源码解析
java·开发语言
Maỿbe13 分钟前
手动实现LinkedList
java·开发语言
爱喝一杯白开水15 分钟前
java基础从入门到上手(九):Java - List、Set、Map
java·list·set·map
JustHappy18 分钟前
「软件设计模式杂谈🤔」和后端吵架失败了,于是乎我写了个适配器模式
前端·javascript·设计模式
掉鱼的猫19 分钟前
MCP Server Java 开发框架的体验比较(spring ai mcp 和 solon ai mcp)
java·mcp
star _chen23 分钟前
如何优雅地实现全局唯一?深入理解单例模式
c++·单例模式·设计模式
静独善水23 分钟前
`ImadcnIdentifierGenerator` 深度解析
java
葵续浅笑41 分钟前
Spring之我见 - Spring Boot Starter 自动装配原理
java·spring boot·spring·自动装配
匹马夕阳1 小时前
Java中订阅消费模式(发布-订阅模式)和观察者模式的区别
java·开发语言·观察者模式
匹马夕阳1 小时前
(二十六)Java观察者模式在Android开发中的应用详解
android·java·观察者模式