代理模式详解

1.基本介绍

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

2.示意图

3.静态代理

3.1 基本介绍

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

3.2 应用实例

3.2.1 基本要求

tex 复制代码
1) 定义一个接口:ITeacherDao 
2) 目标对象 TeacherDAO 实现接口 ITeacherDAO 
3) 使用静态代理方式,就需要在代理对象 TeacherDAOProxy 中也实现 ITeacherDAO 
4) 调用的时候通过调用代理对象的方法来调用目标对象.
5) 特别提醒:代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法

3.2.2 类图

3.2.3 代码实现

java 复制代码
//接口
public interface ITeacherDao {
    public void teach();//授课的方法
}


public class TeacherDao implements ITeacherDao {
 
    @Override
    public void teach() {
        System.out.println(" 老师授课中... ");
    }
}


//代理对象,静态代理
public class TeacherDaoProxy implements ITeacherDao {
    ITeacherDao target;//目标对象,通过接口来聚合
 
    //构造器
    public TeacherDaoProxy(ITeacherDao target) {
        this.target = target;
    }
 
    @Override
    public void teach() {
        System.out.println("静态代理开始,完成某些操作...");//方法
        target.teach();
        System.out.println("静态代理提交...");//方法
    }
}


public class Client {
    public static void main(String[] args) {
        //创建目标对象(被代理对象)
        TeacherDao teacherDao = new TeacherDao();
 
        //创建代理对象, 同时将被代理对象传递给代理对象
        TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
 
        //通过代理对象,调用到被代理对象的方法
        //即:执行的是代理对象的方法,代理对象再去调用目标对象的方法
        teacherDaoProxy.teach();
    }
}

3.3 优缺点

  1. 优点:在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展
  2. 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类
  3. 一旦接口增加方法,目标对象与代理对象都要维护

4.动态代理

4.1 基本介绍

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

4.2 应用实例

4.2.1 类图

4.2.2 代码实现

java 复制代码
//接口
public interface ITeacherDao {
    public void teach();//授课的方法
    public void sayHello(String name);
}

// 目标类
public class TeacherDao implements ITeacherDao {
 
    @Override
    public void teach() {
        System.out.println(" 老师授课中... ");
    }
 
    @Override
    public void sayHello(String name) {
        System.out.println("Hello," + name);
    }
}

// 代理工厂,负责生成代理对象
public class ProxyFactory {
    //维护一个目标对象(被代理对象),Object
    Object target;
 
    //构造器,对target进行初始化
    public ProxyFactory(Object target) {
        this.target = target;
    }
 
    //给目标对象(被代理对象)生成一个代理对象
    public Object getProxyInstance() {
        //说明
		/*
		 *  public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
            //1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
            //2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
            //3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
		 */
        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 returnVal = method.invoke(target, args);
                        System.out.println("JDK代理提交");
                        return returnVal;
                }
        });
    }
}


public class Client {
    public static void main(String[] args) {
        //创建目标对象
        ITeacherDao target = new TeacherDao();
 
        //给目标对象,创建代理对象, 可以转成 ITeacherDao
        ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
 
        // proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
        System.out.println("proxyInstance=" + proxyInstance.getClass());
 
        //通过代理对象,调用目标对象的方法
        proxyInstance.teach();
        proxyInstance.sayHello("Jack");
    }
}

4.3 手动模拟实现底层原理

先定义一个Foo接口,里面有一个foo()方法,再定义一个Target类来实现这个接口

第一版:定义一个类也同样地实现一下Foo接口,然后在foo()方法中编写增强代码,接着再new一个Target对象,调用它的foo()方法,代码如下所示:

java 复制代码
public class Main {
    public static void main(String[] args) {
        Foo proxy=new $Proxy0();
        proxy.foo();
        // 结果:
        // 代码增强
 	    // target foo() 
    }
}

interface Foo{
    void foo();
}

class Target implements Foo{

    @Override
    public void foo() {
        System.out.println(" target foo() ");
    }
}

class $Proxy0 implements Foo{

    @Override
    public void foo() {
        System.out.println("代码增强");
        new Target().foo();
    }
}

第二版:上面的代码把功能增强的代码和调用目标的代码都固定在了代理类的内部,不太灵活。因此可以通过定义一个InvocationHandler接口的方式来将这部分代码解耦出来,代码如下:

java 复制代码
public class Main {
    public static void main(String[] args) {
        Foo proxy=new $Proxy0(new InvocationHandler() {
            @Override
            public void invoke() {
                System.out.println("代码增强");
                new Target().foo();
            }
        });
        proxy.foo();
        // 结果:
        // 代码增强
 	    // target foo() 
    }
}

interface Foo{
    void foo();
}

class Target implements Foo{

    @Override
    public void foo() {
        System.out.println(" target foo() ");
    }
}

class $Proxy0 implements Foo{
    private InvocationHandler h;

    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }

    @Override
    public void foo() {
        h.invoke();
    }
}

interface InvocationHandler{
    void invoke();
}

第三版:第2个版本的代码虽然将功能增强的代码和调用目标的代码通过接口的方式独立出来了,但还是有问题,如果此时接口中新增了一个方法bar(),Target类和$Proxy0类中都要实现bar()方法,那么调用proxy的foo()和bar()方法都将间接调用目标对象的foo()方法,因为在InvocationHandler的invoke()方法中调用的是target.foo()方法,代码如下:

java 复制代码
public interface InvocationHandler {
    void invoke();
}

public interface Foo {
    void foo();
    void bar();
}

@Slf4j
public final class Target implements Foo {
    public void foo() {
        System.out.println("target foo");
    }

    @Override
    public void bar() {
        log.debug("target bar");
    }
}

public class $Proxy0 implements Foo {
    private InvocationHandler h;

    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }

    @Override
    public void foo() {
        h.invoke();
    }

    @Override
    public void bar() {
        h.invoke();
    }
}

public class Main {
    public static void main(String[] args) {
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public void invoke() {
                // 1. 功能增强
                System.out.println("before...");
                // 2. 调用目标
                new Target().foo();
            }
        });
        proxy.foo();
        proxy.bar();
    }
}

改进方法是,代理类中调用方法的时候,通过反射把接口中对应的方法Method对象作为参数传给InvocationHandler,代码如下:

java 复制代码
public class Main {
    public static void main(String[] args) {
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public void invoke(Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
                // 1. 功能增强
                System.out.println("代码增强");
                // 2. 调用目标
                method.invoke(new Target(), args);
            }
        });
        proxy.foo();
        proxy.bar();
        // 结果:
        // 代码增强
 	    // target foo() 
        // 代码增强
        // target bar() 
    }
}

interface Foo {
    void foo();

    void bar();
}

class Target implements Foo {

    @Override
    public void foo() {
        System.out.println(" target foo() ");
    }

    @Override
    public void bar() {
        System.out.println(" target bar() ");
    }
}

class $Proxy0 implements Foo {
    private InvocationHandler h;

    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }

    @Override
    public void foo() {
        try {
            Method foo = Foo.class.getDeclaredMethod("foo");
            h.invoke(foo, new Object[0]);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    @Override
    public void bar() {
        try {
            Method bar = Foo.class.getDeclaredMethod("bar");
            h.invoke(bar, new Object[0]);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

interface InvocationHandler {
    void invoke(Method method, Object[] args) throws Throwable;
}

第四版:第3个版本的代码其实已经离jdk动态代理生成的代码很相近了,为了更好地学习底层,更近一步,修改Foo接口的中bar()方法,使其具有int类型的返回值,因此InvocationHandlerinvoke()方法也得有返回值,同时将代理对象本身作为第一个参数,具体代码如下:

java 复制代码
public class Main {
    public static void main(String[] args) {
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
                // 1. 功能增强
                System.out.println("代码增强");
                // 2. 调用目标
                return method.invoke(new Target(), args);
            }
        });
        proxy.foo();
        System.out.println(proxy.bar());
    }
}

interface Foo {
    void foo();

    int bar();
}

class Target implements Foo {

    @Override
    public void foo() {
        System.out.println(" target foo() ");
    }

    @Override
    public int bar() {
        System.out.println(" target bar() ");
        return 100;
    }
}

class $Proxy0 implements Foo {
    static Method foo;
    static Method bar;

    static {
        try {
            foo = Foo.class.getDeclaredMethod("foo");
            bar = Foo.class.getDeclaredMethod("bar");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

    private InvocationHandler h;

    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }

    @Override
    public void foo() {
        try {
            h.invoke(this, foo, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable e) {
            // 如果抛出RuntimeExcepton,Error和声明的异常以及其子类外的其他异常,
            // 都会被统一转换成 UndeclaredThrowableException 进行抛出,
            // 这也是实现"子类不能抛出比父类更广泛异常"的规则
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public int bar() {
        try {
            return (int) h.invoke(this, bar, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}

interface InvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

到这里跟jdk的动态代理只有些微差距了,jdk的动态代码会让代理类再继承一个Proxy类,里面定义了一个InvocationHandler接口的对象,代理类中会通过super(h)调用父类Proxy的构造。

5.cglib代理

5.1 基本介绍

  1. 静态代理和 JDK代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是Cglib 代理

  2. Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书也将Cglib代理归属到动态代理。

  3. Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 java 类与实现 java 接口.它广泛的被许多 AOP 的框架使用,例如 Spring AOP,实现方法拦截

  4. 在AOP 编程中如何选择代理模式:

    ①目标对象需要实现接口,用 JDK代理

    ②目标对象不需要实现接口,用 Cglib 代理

  1. Cglib 包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类

5.2 注意事项

①在内存中动态构建子类,注意代理的类不能为 final,否则报错 java.lang.IllegalArgumentException:

②目标对象的方法如果为 final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

5.3 应用实例

5.3.1 类图

5.3.2 代码实现

java 复制代码
public class Main {
    public static void main(String[] args) {
        //创建目标对象
        TeacherDao target = new TeacherDao();

        //获取到代理对象,并且将目标对象传递给代理对象
        TeacherDao proxyInstance = (TeacherDao) new ProxyFactory(target).getProxyInstance();

        //执行代理对象的方法,触发intercept 方法,从而实现 对目标对象的调用
        proxyInstance.teach();
        // 结果:
        //Cglib代理模式 ~~ 开始
        // 老师授课中, 使用cglib代理,不需要实现接口... 
        //Cglib代理模式 ~~ 提交
    }
}


class TeacherDao {

    public void teach() {
        System.out.println(" 老师授课中, 使用cglib代理,不需要实现接口... ");
    }
}

class ProxyFactory implements MethodInterceptor {
    //维护一个目标对象(被代理对象),Object
    Object target;

    //构造器,对target进行初始化
    public ProxyFactory(Object target) {
        this.target = target;
    }

    //返回一个代理对象:  是 target 对象的代理对象
    public Object getProxyInstance() {
        //1. 创建一个工具类
        Enhancer enhancer = new Enhancer();
        //2. 设置父类
        enhancer.setSuperclass(target.getClass());
        //3. 设置回调函数
        enhancer.setCallback(this);
        //4. 创建子类对象,即代理对象
        return enhancer.create();
    }

    //重写  intercept 方法,会调用目标对象的方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理模式 ~~ 开始");
        
        // 采用反射调用的方式
        Object returnVal = method.invoke(target, objects);
        // 内部没有反射调用,但需要结合目标对象使用
        // Object returnVal = methodProxy.invoke(target, objects);
        // 内部没有反射调用,但需要结合代理对象使用
        // Object returnVal = methodProxy.invokeSuper(o, args);
        
        System.out.println("Cglib代理模式 ~~ 提交");
        return returnVal;
    }
}

5.4 手动模拟实现底层原理

采用反射调用的方式

java 复制代码
public class Main {
    public static void main(String[] args) {
        Target target = new Target();

        Proxy proxy = new Proxy();
        proxy.setMethodInterceptor(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("before");
                // 反射调用
                return method.invoke(target, args);
            }
        });

        proxy.save();
        proxy.save(1);
        proxy.save(2L);
        // before
        // save()
        // before
        // save(int)
        // before
        // save(long)
    }
}

// 目标类
class Target {
    public void save() {
        System.out.println("save()");
    }

    public void save(int i) {
        System.out.println("save(int)");
    }

    public void save(long i) {
        System.out.println("save(long)");
    }
}

class Proxy extends Target {

    private MethodInterceptor methodInterceptor;

    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    static Method save0;
    static Method save1;
    static Method save2;

    static {
        try {
            save0 = Target.class.getMethod("save");
            save1 = Target.class.getMethod("save", int.class);
            save2 = Target.class.getMethod("save", long.class);
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

    @Override
    public void save() {
        try {
            methodInterceptor.intercept(this, save0, new Object[0], null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this, save1, new Object[]{i}, null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(long i) {
        try {
            methodInterceptor.intercept(this, save2, new Object[]{i}, null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}

在 CGLib 动态代理中,可以使用 intercept() 方法中 MethodProxy 类型的参数实现不经过反射来调用方法。接收的 MethodProxy 类型的参数可以像 Method 类型的参数一样,在静态代码块中被实例化。可以通过静态方法 MethodProxy.create() 来创建 MethodProxy 对象。内部没有反射调用,但需要结合目标对象或者代理对象结合使用:

java 复制代码
public class Main {
    public static void main(String[] args) {
        Target target = new Target();

        Proxy proxy = new Proxy();
        proxy.setMethodInterceptor(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("before");
                // 内部没有反射调用,但需要结合目标对象使用
//                return methodProxy.invoke(target, args);
                // 内部没有反射调用,但需要结合代理对象使用
                return methodProxy.invokeSuper(o, args);
            }
        });

        proxy.save();
        proxy.save(1);
        proxy.save(2L);
        //before
        //save()
        //before
        //save(int)
        //before
        //save(long)
    }
}

// 目标类
class Target {
    public void save() {
        System.out.println("save()");
    }

    public void save(int i) {
        System.out.println("save(int)");
    }

    public void save(long i) {
        System.out.println("save(long)");
    }
}

class Proxy extends Target {

    private MethodInterceptor methodInterceptor;

    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    static Method save0;
    static Method save1;
    static Method save2;
    static MethodProxy save0Proxy;
    static MethodProxy save1Proxy;
    static MethodProxy save2Proxy;

    static {
        try {
            save0 = Target.class.getMethod("save");
            save1 = Target.class.getMethod("save", int.class);
            save2 = Target.class.getMethod("save", long.class);

            save0Proxy = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper");
            save1Proxy = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper");
            save2Proxy = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

    // >>>>>>>>>>>>>>>>>>>>>>>> 带原始功能的方法
    public void saveSuper() {
        super.save();
    }

    public void saveSuper(int i) {
        super.save(i);
    }

    public void saveSuper(long i) {
        super.save(i);
    }


    // >>>>>>>>>>>>>>>>>>>>>>>> 带增强功能的方法
    @Override
    public void save() {
        try {
            methodInterceptor.intercept(this, save0, new Object[0], save0Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this, save1, new Object[]{i}, save1Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(long i) {
        try {
            methodInterceptor.intercept(this, save2, new Object[]{i}, save2Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}

5.5 MethodProxy 原理

调用 methodProxy.invoke() 方法时,会额外使用一个代理类,该代理类配合目标对象使用。调用 methodProxy.invokeSuper() 方法时,也会额外使用一个代理类,该代理类配合代理对象使用。当调用 MethodProxy 对象的 invoke() 方法或 invokeSuper() 方法时,就会生成这两个代理类,它们都继承至 FastClass。FastClass 是一个抽象类,其内部有多个抽象方法:

java 复制代码
public abstract class FastClass {
    public abstract int getIndex(String var1, Class[] var2);
  
    public abstract int getIndex(Class[] var1);

    public abstract Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException;

    public abstract Object newInstance(int var1, Object[] var2) throws InvocationTargetException;

    public abstract int getIndex(Signature signature);

    public abstract int getMaxIndex();
}

重点讲解 invoke() 方法与 getIndex(Signature signature) 方法。

模拟生成的与目标类相关的代理类:

java 复制代码
public class TargetFastClass {

    static Signature s0 = new Signature("save", "()V");
    static Signature s1 = new Signature("save", "(I)V");
    static Signature s2 = new Signature("save", "(J)V");

    /**
     * <p>获取目标方法的编号</p>
     * <p>
     * Target 目标类中的方法:
     * save()             0
     * save(int)          1
     * save(long)         2
     * </p>
     *
     * @param signature 包含方法名称、参数返回值
     * @return 方法编号
     */
    public int getIndex(Signature signature) {
        if (s0.equals(signature)) {
            return 0;
        }
        if (s1.equals(signature)) {
            return 1;
        }
        if (s2.equals(signature)) {
            return 2;
        }
        return -1;
    }

    /**
     * 根据 getIndex() 方法返回的方法编号正常调用目标对象方法
     *
     * @param index       方法编号
     * @param target       目标对象
     * @param args 调用目标对象方法需要的参数
     * @return 方法返回结果
     */
    public Object invoke(int index, Object target, Object[] args) {
        if (index == 0) {
            ((Target) target).save();
            return null;
        }
        if (index == 1) {
            ((Target) target).save((int) args[0]);
            return null;
        }
        if (index == 2) {
            ((Target) target).save((long) args[0]);
            return null;
        }
        throw new RuntimeException("无此方法");
    }

    public static void main(String[] args) {
        TargetFastClass fastClass = new TargetFastClass();
        int index = fastClass.getIndex(new Signature("save", "()V"));
        fastClass.invoke(index, new Target(), new Object[0]);

        index = fastClass.getIndex(new Signature("save", "(J)V"));
        fastClass.invoke(index, new Target(), new Object[]{2L});
        // 结果:
        // save()
        // save(long)
    }
}

模拟生成的与代理类相关的代理类

java 复制代码
public class ProxyFastClass {
    static Signature s0 = new Signature("saveSuper", "()V");
    static Signature s1 = new Signature("saveSuper", "(I)V");
    static Signature s2 = new Signature("saveSuper", "(J)V");

    /**
     * <p>获取代理方法的编号</p>
     * <p>
     * Proxy 代理类中的方法:
     * saveSuper()             0
     * saveSuper(int)          1
     * saveSuper(long)         2
     * </p>
     *
     * @param signature 包含方法名称、参数返回值
     * @return 方法编号
     */
    public int getIndex(Signature signature) {
        if (s0.equals(signature)) {
            return 0;
        }
        if (s1.equals(signature)) {
            return 1;
        }
        if (s2.equals(signature)) {
            return 2;
        }
        return -1;
    }

    /**
     * 根据 getIndex() 方法返回的方法编号正常调用代理对象中带原始功能的方法
     *
     * @param index 方法编号
     * @param proxy 代理对象
     * @param args  调用方法需要的参数
     * @return 方法返回结果
     */
    public Object invoke(int index, Object proxy, Object[] args) {
        if (index == 0) {
            ((Proxy) proxy).saveSuper();
            return null;
        }
        if (index == 1) {
            ((Proxy) proxy).saveSuper((int) args[0]);
            return null;
        }
        if (index == 2) {
            ((Proxy) proxy).saveSuper((long) args[0]);
            return null;
        }
        throw new RuntimeException("无此方法");
    }

    public static void main(String[] args) {
        ProxyFastClass fastClass = new ProxyFastClass();
        int index = fastClass.getIndex(new Signature("saveSuper", "()V"));
        fastClass.invoke(index, new Proxy(), new Object[0]);
        // 结果:
        // save()
    }
}

与 JDK 中优化反射调用方法的对比

tex 复制代码
在 JDK 中需要反射调用 16 次方法后才会生成优化反射调用的代理类,而在 CGLib 中,当调用 MethodProxy.create() 方法时就会生成由于优化反射调用的代理类;
在 JDK 中一个方法的反射调用优化就要生成一个代理类,而在 CGLib 中,一个代理类生成两个 FastClass 代理类。

6.代理模式的常见变体

  1. 防火墙代理: 内网通过代理穿透防火墙,实现对公网的访问。
  2. 缓存代理: 比如:当请求图片文件等资源时,先到缓存代理取,如果取到资源则 ok,如果取不到资源,再到公网或者数据
    库取,然后缓存。
  3. 远程代理 远程对象的本地代表,通过它可以把远程对象当本地对象来调用。远程代理通过网络和真正的远程对象沟通信息。
  4. 同步代理:主要使用在多线程编程中,完成多线程间同步工作
    同步代理:主要使用在多线程编程中,完成多线程间同步工作

).saveSuper((int) args[0]);

return null;

}

if (index == 2) {

((Proxy) proxy).saveSuper((long) args[0]);

return null;

}

throw new RuntimeException("无此方法");

}

public static void main(String[] args) {
    ProxyFastClass fastClass = new ProxyFastClass();
    int index = fastClass.getIndex(new Signature("saveSuper", "()V"));
    fastClass.invoke(index, new Proxy(), new Object[0]);
    // 结果:
    // save()
}

}

### 与 JDK 中优化反射调用方法的对比

```tex
在 JDK 中需要反射调用 16 次方法后才会生成优化反射调用的代理类,而在 CGLib 中,当调用 MethodProxy.create() 方法时就会生成由于优化反射调用的代理类;
在 JDK 中一个方法的反射调用优化就要生成一个代理类,而在 CGLib 中,一个代理类生成两个 FastClass 代理类。

6.代理模式的常见变体

  1. 防火墙代理: 内网通过代理穿透防火墙,实现对公网的访问。
  2. 缓存代理: 比如:当请求图片文件等资源时,先到缓存代理取,如果取到资源则 ok,如果取不到资源,再到公网或者数据
    库取,然后缓存。
  3. 远程代理 远程对象的本地代表,通过它可以把远程对象当本地对象来调用。远程代理通过网络和真正的远程对象沟通信息。
  4. 同步代理:主要使用在多线程编程中,完成多线程间同步工作
    同步代理:主要使用在多线程编程中,完成多线程间同步工作
相关推荐
OkeyProxy8 小时前
什麼是ISP提供的公共IP地址?
代理模式·proxy模式·ip地址·isp·海外ip代理
kikyo哎哟喂18 小时前
Java 代理模式详解
java·开发语言·代理模式
hxj..1 天前
【设计模式】代理模式
java·设计模式·代理模式·动态代理
武子康2 天前
Java-05 深入浅出 MyBatis - 配置深入 动态 SQL 参数、循环、片段
java·sql·设计模式·架构·mybatis·代理模式
武子康3 天前
Java-04 深入浅出 MyBatis - SqlSessionFactory 与 SqlSession DAO与Mapper 代理模式
java·mysql·spring·mybatis·springboot·代理模式
南城花随雪。4 天前
Mybatis框架之代理模式 (Proxy Pattern)
mybatis·代理模式
JhonKI6 天前
【算法】动态规划中01背包问题解析
算法·动态规划·代理模式
OkeyProxy7 天前
如何恢復電腦IP地址的手動設置?
代理模式·ip·ip地址·代理服务器·海外ip代理
无限大.10 天前
动态规划与贪心算法:核心区别与实例分析
贪心算法·动态规划·代理模式
丶Darling.11 天前
Day42 | 动态规划 :选或不选 打家劫舍&&打家劫舍II
算法·动态规划·代理模式