JDK动态代理

代理

一般是代理对象持有被代理对象,然后在代理对象中加一些额外的处理逻辑,然后在真实对象调用前后执行。

JDK动态代理

代理对象和被代理对象实现同一套接口,然后调用代理对象的方法,实际上执行代理对象添加的逻辑和被代理对象的逻辑。特殊说明:代理对象是动态生成的。

话不多说,直接上代码。对JDK动态代理比较熟的同学,可以略过前面几个类,重点看一下InvocationHandler的实现类(InvocationHandlerImpl)和代理生成的字节码($Proxy0),里面注释基本上都写了。

第一个接口类

package wz_ling.learning.proxy;

public interface PlayDemo {
    void playGame(String game);
}

第二个接口类

package wz_ling.learning.proxy;

public interface SayDemo {
    String sayGoodBye();
}

被代理对象(真实对象)

package wz_ling.learning.proxy;

public class RealObject implements SayDemo, PlayDemo {
    @Override
    public String sayGoodBye() {
        return "goodbye RealObject";
    }
    @Override
    public void playGame(String game) {
        System.out.println("play game[" + game + "]");
    }
}

InvocationHandler的实现类,实际持有被代理对象。

package wz_ling.learning.proxy;

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

public class InvocationHandlerImpl implements InvocationHandler {
    /**
     * 被代理对象
     */
    private Object realObject;

    public InvocationHandlerImpl(Object realObject) {
        this.realObject = realObject;
    }

    /**
     * 1、重写InvocationHandler方法
     * 2、代理的前后逻辑都是在重写invoke方法中实现
     *
     * @param proxy  被代理对象
     * @param method 目标方法
     * @param args   方法参数
     * @return
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before proxy");
        Object invoke = method.invoke(realObject, args);
        System.out.println("after proxy");
        return invoke;
    }
}

ProxyDemo类

package wz_ling.learning.proxy;

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

public class ProxyDemo {
    public static void main(String[] args) {
        //设置保存动态生成的class文件,在com.sun.proxy包下
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //代理的真实对象
        RealObject realSubject = new RealObject();
        //代理逻辑织入的地方
        InvocationHandler handler = new InvocationHandlerImpl(realSubject);

        ClassLoader loader = realSubject.getClass().getClassLoader();
        Class<?>[] interfaces = realSubject.getClass().getInterfaces();

        Object proxy = Proxy.newProxyInstance(loader, interfaces, handler);
        //以下演示了代理成不同的类型
        SayDemo sayProxy = (SayDemo) proxy;
        sayProxy.sayGoodBye();
        PlayDemo playDemo = (PlayDemo) proxy;
        playDemo.playGame("真~三国无双");
    }
}

代理生成的字节码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

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 wz_ling.learning.proxy.PlayDemo;
import wz_ling.learning.proxy.SayDemo;

//代理类实现了和被代理对象一样的接口
//代理类继承了Proxy类
public final class $Proxy0 extends Proxy implements SayDemo, PlayDemo {
   	//在静态块中初始化了下面的几个Method(m1,m2,m3...)
   	//翻到最下面的静态块,可以看到m3、m4就是被代理对象实现的接口的方法
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;

	//代理类在初始化时设置InvocationHandler(我们需要自己实现该接口,重写invoke方法,即上面的InvocationHandlerImpl的实现类)
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

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

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String sayGoodBye() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void playGame(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("wz_ling.learning.proxy.SayDemo").getMethod("sayGoodBye");
            m4 = Class.forName("wz_ling.learning.proxy.PlayDemo").getMethod("playGame", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

关键代码:

Object proxy = Proxy.newProxyInstance(loader, interfaces, handler);

第一个参数,类加载器
第二个参数,接口列表
第三个参数,调用处理器,入参是InvocationHandler接口类,需要自己实现该类,重写该接口。

在看代理生成的字节码,继承了Proxy类,同时实现了入参接口列表中的所有接口,在看$Proxy0的构造器,入参就是上面的第3个参数,即我们自己实现的InvocationHandler接口类,最终调用了父类Proxy的有参构造器,所以最终代理类是持有InvocationHandler实现类,而实现类又持有了被代理类。

	public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

再看调用代码

	SayDemo sayProxy = (SayDemo) proxy;
	sayProxy.sayGoodBye();

实际执行的是代理类$Proxy0中的sayGoodBye()方法

    public final String sayGoodBye() throws  {
        try {
        	//调用的是InvocationHandler的invoke方法,即我们自己重写的InvocationHandler的方法
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

所以,到这里也可以回到一个经典的问题,为什么JDK的动态代理必须实现接口而不能是继承被代理类?
两个方面:
1、从实现上来看,入参就需要接口列表,代理对象也实现同样的接口,如果没有接口,那么怎么调用呢?
2、代理类已经继承了Proxy类,java单继承。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值