java 设计模式之代理模式

news2025/4/21 20:20:53

简介

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

代理模式内部的角色:

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

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

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

代理模式的分类

静态代理

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

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

第一步:目标接口

public interface SellTickets {
    void sell();
}

第二步:目标类

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

第三步:代理类

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();
    }
}

测试:

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

动态代理

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

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

基于jdk的动态代理技术

jdk原生的动态代理技术

案例:

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

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

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);
    }
}

测试:

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提供了一种动态代理技术,它是基于继承关系,目标类不需要实现接口。

案例:

第一步:添加依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

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

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

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();
    }
}

测试:

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

原理解析

查看创建出的代理类

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

案例:

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在内存中动态创建的代理类的字节码,

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创建的代理类

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

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万次,每一次都创建一个代理类,然后调用一次代理类中的方法,方法中什么都不做,这里只关心方法的调用速度

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万个代理类,每个代理类都执行一次112ms1130ms
创建1个代理类,每个代理类都执行100万次29ms34ms

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

源码解析

jdk创建代理的方式

API总结:

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

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:调用处理器,在调用处理器中调用增强方法和目标对象。每个代理实例有一个相关联的调用处理器,代理对象内部实际上是通过调用处理器来工作的

public interface InvocationHandler {

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2339649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

外接键盘与笔记本命令键键位不同解决方案(MacOS)

文章目录 修改键位第一步&#xff1a;打开设置第二步&#xff1a;进入键盘快捷键第三步&#xff1a;修改修饰键设置第四步&#xff1a;调整键位第五步&#xff1a;保存设置tips ikbc c87键盘win键盘没反应的解决亲测的方法这是百度的答案标题常规组合键尝试‌&#xff1a;型号差…

kotlin知识体系(五) :Android 协程全解析,从作用域到异常处理的全面指南

1. 什么是协程 协程(Coroutine)是轻量级的线程&#xff0c;支持挂起和恢复&#xff0c;从而避免阻塞线程。 2. 协程的优势 协程通过结构化并发和简洁的语法&#xff0c;显著提升了异步编程的效率与代码质量。 2.1 资源占用低&#xff08;一个线程可运行多个协程&#xff09;…

vscode stm32 variable uint32_t is not a type name 问题修复

问题 在使用vscodekeil开发stm32程序时&#xff0c;发现有时候vscode的自动补全功能失效&#xff0c;且problem窗口一直在报错。variable “uint32_t” is not a type name uint32_t 定义位置 uint32_t 实际是在D:/Keil_v5/ARM/ARMCC/include/stdint.h中定义的。将D:/Keil_v5…

Formality:Bug记录

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 本文记录博主在使用Synopsys的形式验证工具Formality中遇到的一个Bug。 Bug复现 情况一 // 例1 module dff (input clk, input d_in, output d_out …

【java+Mysql】学生信息管理系统

学生信息管理系统是一种用于管理学生信息的软件系统&#xff0c;旨在提高学校管理效率和服务质量。本课程设计报告旨在介绍设计和实现学生信息管理系统的过程。报告首先分析了系统的需求&#xff0c;包括学生基本信息管理、成绩管理等功能。接着介绍了系统的设计方案&#xff0…

小白从0学习网站搭建的关键事项和避坑指南(2)

以下是针对小白从零学习网站搭建的 进阶注意事项和避坑指南&#xff08;第二期&#xff09;&#xff0c;覆盖开发中的高阶技巧、常见陷阱及解决方案&#xff0c;帮助你在实战中提升效率和质量&#xff1a; 一、进阶技术选型避坑 1. 前端框架选择 误区&#xff1a;盲目追求最新…

Windows 10 上安装 Spring Boot CLI详细步骤

在 Windows 10 上安装 Spring Boot CLI 可以通过以下几种方式完成。以下是详细的步骤说明&#xff1a; 1. 手动安装&#xff08;推荐&#xff09; 步骤 1&#xff1a;下载 Spring Boot CLI 访问 Spring Boot CLI 官方发布页面。下载最新版本的 .zip 文件&#xff08;例如 sp…

vue2技术练习-开发了一个宠物相关的前端静态商城网站-宠物商城网站

为了尽快学习掌握相关的前端技术&#xff0c;最近又实用 vue2做了一个宠物行业的前端静态网站商城。还是先给大家看一下相关的网站效果&#xff1a; 所以大家如果想快速的学习或者掌握一门编程语言&#xff0c;最好的方案就是通过学习了基础编程知识后&#xff0c;就开始利用…

嵌入式学习——远程终端登录和桌面访问

目录 通过桥接模式连接虚拟机和Windows系统 1、桥接模式 2、虚拟机和Windows连接&#xff08;1&#xff09; 3、虚拟机和Windows连接&#xff08;2&#xff09; 在Linux虚拟机中创建新用户 Windows系统环境下对Linux系统虚拟机操作 远程登录虚拟机&#xff08;1&#xff…

如何新建一个空分支(不继承 master 或任何提交)

一、需求分析&#xff1a; 在 Git 中&#xff0c;我们通常通过 git branch 来新建分支&#xff0c;这些分支默认都会继承当前所在分支的提交记录。但有时候我们希望新建一个“完全干净”的分支 —— 没有任何提交&#xff0c;不继承 master 或任何已有内容&#xff0c;这该怎么…

Qt编写推流程序/支持webrtc265/从此不用再转码/打开新世界的大门

一、前言 在推流领域&#xff0c;尤其是监控行业&#xff0c;现在主流设备基本上都是265格式的视频流&#xff0c;想要在网页上直接显示监控流&#xff0c;之前的方案是&#xff0c;要么转成hls&#xff0c;要么魔改支持265格式的flv&#xff0c;要么265转成264&#xff0c;如…

[第十六届蓝桥杯 JavaB 组] 真题 + 经验分享

A&#xff1a;逃离高塔(AC) 这题就是简单的签到题&#xff0c;按照题意枚举即可。需要注意的是不要忘记用long&#xff0c;用int的话会爆。 &#x1f4d6; 代码示例&#xff1a; import java.io.*; import java.util.*; public class Main {public static PrintWriter pr ne…

深⼊理解 JVM 执⾏引擎

深⼊理解 JVM 执⾏引擎 其中前端编译是在 JVM 虚拟机之外执⾏&#xff0c;所以与 JVM 虚拟机没有太⼤的关系。任何编程语⾔&#xff0c;只要能够编译出 满⾜ JVM 规范的 Class ⽂件&#xff0c;就可以提交到 JVM 虚拟机执⾏。⾄于编译的过程&#xff0c;如果你不是想要专⻔去研…

iwebsec靶场 文件包含关卡通关笔记11-ssh日志文件包含

目录 日志包含 1.构造恶意ssh登录命令 2.配置ssh日志开启 &#xff08;1&#xff09;配置sshd &#xff08;2&#xff09;配置rsyslog &#xff08;3&#xff09;重启服务 3.写入webshell木马 4.获取php信息渗透 5.蚁剑连接 日志包含 1.构造恶意ssh登录命令 ssh服务…

kafka菜鸟教程

一、kafka原理 1、kafka是一个高性能的消息队列系统&#xff0c;能够处理大规模的数据流&#xff0c;并提供低延迟的数据传输&#xff0c;它能够以每秒数十万条消息的速度进行读写操作。 二、kafka优点 1、服务解耦 &#xff08;1&#xff09;提高系统的可维护性‌ 通过服务…

应用镜像是什么?轻量应用服务器的镜像大全

应用镜像是轻量应用服务器专属的&#xff0c;镜像就是轻量应用服务器的装机盘&#xff0c;应用镜像在原有的纯净版操作系统上集成了应用程序&#xff0c;例如WordPress应用镜像、宝塔面板应用镜像、WooCommerce等应用&#xff0c;阿里云服务器网aliyunfuwuqi.com整理什么是轻量…

深入理解分布式缓存 以及Redis 实现缓存更新通知方案

一、分布式缓存简介 1. 什么是分布式缓存 分布式缓存&#xff1a;指将应用系统和缓存组件进行分离的缓存机制&#xff0c;这样多个应用系统就可以共享一套缓存数据了&#xff0c;它的特点是共享缓存服务和可集群部署&#xff0c;为缓存系统提供了高可用的运行环境&#xff0c…

Spring Boot 中的自动配置原理

2025/4/6 向全栈工程师迈进&#xff01; 一、自动配置 所谓的自动配置原理就是遵循约定大约配置的原则&#xff0c;在boot工程程序启动后&#xff0c;起步依赖中的一些bean对象会自动的注入到IOC容器中。 在讲解Spring Boot 中bean对象的管理的时候&#xff0c;我们注入bean对…

剑指Offer(数据结构与算法面试题精讲)C++版——day16

剑指Offer&#xff08;数据结构与算法面试题精讲&#xff09;C版——day16 题目一&#xff1a;序列化和反序列化二叉树题目二&#xff1a;从根节点到叶节点的路径数字之和题目三&#xff1a;向下的路径节点值之和附录&#xff1a;源码gitee仓库 题目一&#xff1a;序列化和反序…

windows server C# IIS部署

1、添加IIS功能 windows server 2012、windows server 2016、windows server 2019 说明&#xff1a;自带的是.net 4.5 不需要安装.net 3.5 尽量使用 windows server 2019、2016高版本&#xff0c;低版本会出现需要打补丁的问题 2、打开IIS 3、打开iis应用池 .net 4.5 4、添…