从静态代理到JDK动态代理

前言:静态代理和动态代理是一种编程风格、编程范式,也叫设计模式

  1. 静态代理
public class StaticProxy implements Service{
    public static void main(String[] args) {
        StaticProxy staticProxy=new StaticProxy(new DefaultService());
        staticProxy.show();
    }

    private Service service;

    public StaticProxy(Service service){
        this.service=service;
    }

    @Override
    public void show() {
        System.out.println("Before");
        service.show();
        System.out.println("After");
    }
}

interface Service{
    void show();
}

class DefaultService implements Service{

    @Override
    public void show() {
        System.out.println("here is default show");
    }
}

2、 动态代理

public class JdkDynamicProxy {
    public static void main(String[] args) {
        byte[] bytes = ProxyGenerator.generateProxyClass("$ProxyDao", new Class[]{Dao.class});
        try {
            FileOutputStream out = new FileOutputStream("C:\\Users\\23317\\Desktop\\$ProxyDao.class");
            out.write(bytes);
        } catch (Exception ex) {
        }

        Object proxy = Proxy.newProxyInstance(JdkDynamicProxy.class.getClassLoader(),
                new Class[]{Dao.class}, new DaoInvocationHandler());

        Dao dao = (Dao) proxy;

        dao.insert("qyd");
    }
}

interface Dao {
    void insert(String name);
}

class DaoImpl implements Dao {

    @Override
    public void insert(String name) {
        System.out.println("insert->" + name);
    }
}

class DaoInvocationHandler implements InvocationHandler {

    private Dao dao = new DaoImpl();

    /**
     * @param proxy  生成的$ProxyDao类的对象
     * @param method $ProxyDao类实现的接口的对应方法
     * @param args   $ProxyDao类实现的接口的对应参数,用户传进来的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("Before");
        method.invoke(dao, args);
        System.out.println("After");
        return null;
    }
}
public final class $ProxyDao extends Proxy implements Dao {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $ProxyDao(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 void insert(String var1) throws  {
        try {
            super.h.invoke(this, m3, 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 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"));
            m3 = Class.forName("club.qydqyj.aop.Dao").getMethod("insert", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

总结:
1、动态代理即jdk帮我们实现了类,按照静态原理代码编写范式,动态代理的类也实现了接口
2、动态代理的类继承了Jdk的Proxy类,这也是jdk动态代理是基于接口的原因,因为java是单继承原则
3、动态代理类不但实现了接口的所有方法,也重写了Object类的equals、hashcode、toString方法
4、按照静态代理的代码编写范式,还需要实现了接口的类作为动态代理类的成员属性,以此来调用真正实现接口的方法。首先需要知道要代理的类应该由用户定义的,如果java设计成动态代理类为需要传进去所有接口的实现类作为参数交给java生成动态代理类,这样虽然也可以,但是显然有点设计过度。所以java设计了InvocationHandler类,java生成的动态代理类的所有重写方法都只调用InvocationHandler#invoke(Object proxy, Method method, Object[] args)方法,把真正接口实现的代码编写交给用户实现,这样明显更合理。
5、InvocationHandler#invoke(Object proxy, Method method, Object[] args)方法参数列表:proxy是java生成的动态代理类;method是接口方法和equals、hashcode、toString方法,args是用户传进去某方法的参数。

上帝视觉:

//1
Object proxy = Proxy.newProxyInstance(JdkDynamicProxy.class.getClassLoader(),
                new Class[]{Dao.class}, new DaoInvocationHandler());
//2
Dao dao = (Dao) proxy;
//3
dao.insert("qyd");

1中的proxy就是Java生成的动态代理类,其实就是上面的$ProxyDao类的对象,这个类实现了接口Dao,当调用insert方法的时候,会调用重写的InvocationHandler类的方法,在这个方法里面,我们可以通过method对象知道当前正在哪个方法上,然后就可以通过method#invoke(要代理的类,args)调用真正实现接口的方法。这里有一个疑惑?为什么InvocationHandler#invoke方法参数会有proxy对象,由上面可以知道这个对象是java生成的动态代理类的对象,想不到有什么场景可以用到它?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值