Java静态代理和动态代理

美发技能:

public interface Hairdressing {

    int haircut();

}

理发师:

public class Barber implements Hairdressing {

    private String name;

    public Barber(String name){
        this.name = name;
    }


    @Override
    public int haircut() {
        System.out.println(name + "老师剪头");
        return 50;
    }
}

理发店(静态代理):

public class Barbershop implements Hairdressing {
    private String barberName;
    private Barber barber;

    public Barbershop(String barberName){
        this.barberName = barberName;
    }

    @Override
    public int haircut() {
        if (barber == null){
            barber = new Barber(barberName);
            System.out.println("先洗头");
            barber.haircut();
            System.out.println("再洗头");
        }
        return 50;
    }
}

测试类:

public class ProxyTest {

    public static void main(String[] args) {

        //静态代理
        Barbershop barbershop = new Barbershop("托尼");
        int money = barbershop.haircut();
        System.out.println("需要付:" + money + "元");
        System.out.println("------------------------------------------");

        //动态代理
        Barber barber = new Barber("托尼");
        Object proxyInstance = Proxy.newProxyInstance(Barber.class.getClassLoader(), Barber.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("先洗头");
                Object o = method.invoke(barber, args);
                System.out.println("再洗头");
                return o;
            }
        });

        Hairdressing hairdressing = (Hairdressing) proxyInstance;
        int money1 = hairdressing.haircut();
        System.out.println("需要付:" + money1 + "元");
        System.out.println("------------------------------------------");
        System.out.println(hairdressing.toString());
    }

}

执行结果

 先介绍一下动态代理的使用:

Object proxyInstance = Proxy.newProxyInstance(Barber.class.getClassLoader(), Barber.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("先洗头");
                Object o = method.invoke(barber, args);
                System.out.println("再洗头");
                return o;
            }
        });

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

三个参数:

第一个:classLoader随便给一个Classloader

第二个:一个数组里面是要代理的所有的接口Class

第三个:InvocationHandler 是一个接口,参数是接口

用法:

通过Proxy.newProxyInstance生成一个代理,代理可以强转成接口类型后,调用接口,当调用接口的时候就会触发InvocationHandler的invoke方法:

invoke(Object proxy, Method method, Object[] args)

三个参数:

第一个:动态代理的实例

第二个:反射Method,这个Method就是上面接口调用的方法的Method

第三个:是上面调用的接口的参数,在这里给Method用的

知道用法后,思考几个问题:
1.这个动态代理对象是什么,怎么得到的,为什么能强转成那些传入的Proxy.newProxyInstance中的第二个参数的接口
2.怎么实现的一调用我们传入Proxy.newProxyInstance中的第二个参数中接口中的方法,就会触发InvocationHandler的invoke方法,并且把调用的那个方法的Method和参数传过来。

带着这两个问题去看源码:

动态代理原理:

实际上, Proxy.newProxyInstance 会创建一个Class,与静态代理不同,这个Class不是由具体的.java源文件编译

而来,即没有真正的文件,只是在内存中按照Class格式生成了一个Class,这个Class就是动态代理类我们反编译后:

public final class Proxy4 extends Proxy
        implements Hairdressing
{
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public Proxy4(InvocationHandler paramInvocationHandler)
            throws
    {
        super(paramInvocationHandler);
    }

    public final boolean equals(Object paramObject)
            throws
    {
        try
        {
            return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (RuntimeException localRuntimeException)
        {
            throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

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


    public int haircut() {
            throws
        {
            try
            {
                return ((Integer)this.h.invoke(this, m3,null));
            }
            catch (RuntimeException localRuntimeException)
            {
                throw localRuntimeException;
            }
            catch (Throwable localThrowable)
            {
                throw new UndeclaredThrowableException(localThrowable);
            }
        }

    public final int hashCode()
            throws
    {
        try
        {
            return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (RuntimeException localRuntimeException)
        {
            throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    static
    {
        try
        {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com/example/fragmentadaptertest/proxy/Hairdressing.java").getMethod("haircut", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
            throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
            throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
    }


}

在此Classclinit(静态代码块与静态属性组成的方法)中,获得 method 备用。

在生成动态代理的Class的时候在static代码块中,把Hairdressing接口中的方法都搞成了method

在上面的例子中就是:m1,m2,m3,m4

而这个代理类中所有方法的实现变为:

    public int haircut() {
            throws
        {
            try {
                return ((Integer) this.h.invoke(this, m3, null));
            } catch (RuntimeException localRuntimeException) {
                throw localRuntimeException;
            } catch (Throwable localThrowable) {
                throw new UndeclaredThrowableException(localThrowable);
            }
        }
    }

首先看this.h是什么,this很明显就是我们的Proxy4的实例,可是Proxy4中没有h这个属性,那我们从父类Proxy中找:

果然父类中有,这个h就是我们调用

Proxy.newProxyInstance(Barber.class.getClassLoader(), Barber.class.getInterfaces(), new InvocationHandler(){})这个方法的第三个参数传进来的InvocationHandler的实例。

通过生成的动态代理类的这个haircut方法可以看到,动态代理每次调用接口中的方法,实际是调用的 this.h.invoke(this, Method method, Object[] args)),也就是我们的InvocationHandler中的ivoke方法。

下面简单看一下源码流程:

从这个Proxy.newProxyInstance看起:

 只搞成主线流程:

看上面我们生成的代理类Proxy4的构造方法,是继承的Proxy的构造方法:

    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

到这里就打通了,通过Proxy.newProxyInstance在内存中生成了一个动态代理的class,并且返回这个class的实例,这个class继承Proxy类,实现了我们传入的Proxy.newProxyInstance的第二个参数接口数组中的所有接口,把第三个参数就是我们的InvocationHandler的实例当作构造函数的参数传入Proxy中维护,在static静态代码块中把接口中所有的方法都搞成method获取到维护在类中备用,在代理类中重写了接口中所有的方法,这些重写的方法的实现都是this.h.invoke(this, Method method, Object[] args)),当动态代理的实例调用接口中的任何一个方法时,通过源码我们看到其实是调用了InvocationHandler的invoke方法。

为什么JDK的动态代理只能代理接口不能代理类

我们生成的代理类的Class源码:public final class Proxy4 extends Proxy implements Hairdressing。生成的代理类默认继承了Proxy这个类,而java中又是单继承的,所以只能代理接口,不能代理类。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值