JDK动态代理

前言

最近在了解spring aop的实现原理,了解到spring aop支持两种代理模式,jdk动态代理和cglib动态代理。

  • jdk动态代理基于反射实现,通过反射创建一个实现代理接口的匿名类,在调用业务方法前调用InvocationHandler处理。代理类必须实现InvocationHandler接口,invoke方法是实现代理逻辑的地方,动态生成的代理类$Proxy0,继承了Proxy代理类,并实现了业务接口,由于java不允许多继承,所有jdk动态代理只能代理接口。
  • cglib动态代理借助asm,通过字节码技术生成代理类,支撑类和接口的代理,具体原理见下篇。

案例

下面通过例子来说明jdk动态代理的应用和原理:

  1. 定义一个抽象主题接口Subject:
/**
 * Subject
 * 抽象主题接口
 **/
public interface Subject {

    void doSomething();
}
  1. 定义真实主题类RealSubject实现Subject:
/**
 * RealSubject
 * 真实主题类
 */
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject do something");
    }
}
  1. 定义CustomerSubjectInvocationHandler实现InvocationHandler接口:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class CustomerSubjectInvocationHandler implements InvocationHandler {
    private Object target;
    public CustomerSubjectInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before proxy do something...");
        Object result = method.invoke(target, args);
        System.out.println("after proxy do something...");
        return result;
    }
}
  1. 测试
import com.study.java.proxy.RealSubject;
import com.study.java.proxy.Subject;
import java.lang.reflect.Proxy;

/**
 * JDKDynamicProxy
 * jdk动态代理测试
 */
public class JDKDynamicProxy {

    public static <T> T getProxy(Object o) {
        return (T) Proxy.newProxyInstance(CustomerSubjectInvocationHandler.class.getClassLoader(), o.getClass().getInterfaces(), new CustomerSubjectInvocationHandler(o));
    }
    public static void main(String[] args) {
        // 保存生成的代理类的字节码文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        Subject subject = JDKDynamicProxy.getProxy(new RealSubject());
        subject.doSomething();
    }
}

运行后打印出结果:

before proxy do something...
RealSubject do something
after proxy do something...

成功实现代理。
通过添加
System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
打印动态生成的代理类:

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

package com.sun.proxy;

import com.study.java.proxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    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 void doSomething() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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("com.study.java.proxy.Subject").getMethod("doSomething");
            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());
        }
    }
}

可以看到$Proxy0就是动态生成的代理类,doSomething是被代理对象的发放,$Proxy0中调用了传入的InvocationHandler的invoke方法区代理执行业务方法,实现代理。$Proxy0继承了Proxy类,同时实现了Subject接口,由此可见为什么jdk动态代理只支持代理接口,因为java不允许多继承,动态代理类$Proxy0已经继承了Proxy类,无法再继承一个类了,只能implements实现多个接口

在上面的案例中可以发现,代理类是通过 Proxy.newProxyInstance获取的, Proxy.newProxyInstance有三个参数newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h),其中
ClassLoader loader:代理对象的类加载器
Class<?>[] interfaces:被代理的一组接口
InvocationHandler h:动态代理对象关联的InvocationHandler 实现类

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值