JDK动态代理原理

springAop 才用了2种动态代理机制,一个是cglib动态代理,一个是jdk动态代理。

今天通过一个例子来追踪一下jdk动态代理原理。


public interface NewsService {

    public void add();

    public void del();
}


public class NewsServiceImpl implements NewsService {

    @Override
    public void add() {
        System.out.println("This is add service");
    }

    @Override
    public void del() {
        System.out.println("This is del service");
    }
}

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

public class MyInvocatioHandler implements InvocationHandler {
    private Object target;

    public MyInvocatioHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----before-----");
        Object result = method.invoke(target, args);
        System.out.println("-----end-----");
        return result;
    }

    // 生成代理对象
    public Object getProxy() {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        return Proxy.newProxyInstance(loader, interfaces, this);
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        NewsService service = new NewsServiceImpl();
        MyInvocatioHandler handler = new MyInvocatioHandler(service);
        NewsService serviceProxy = (NewsService) handler.getProxy();
        serviceProxy.add();
        serviceProxy.del();
    }

控制台的结果是
—–before—–
This is add service
—–end—–
—–before—–
This is del service
—–end—–

下面我们就追一下代码
我们先看一下我们的代理对象是怎么生成的
Proxy.newProxyInstance(loader, interfaces, this);

 @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
       .......
        /*
         * Look up or generate the designated proxy class.
         * 查找或生成指定的代理类
         */
        Class<?> cl = getProxyClass0(loader, interfaces);
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        .....
        final InvocationHandler ih = h;
        .....
        return newInstance(cons, ih);
       .......
    }
private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        ......
        return proxyClassCache.get(loader, interfaces);
    }
 public V get(K key, P parameter) {
        .......
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
......

这里的提到了apply(),是Proxy类的内部类ProxyClassFactory实现其接口的一个方法,具体实现如下:

 @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
       .......
            /*
             * Generate the specified proxy class.
             * 生成指定的代理类
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);

        }
    }

这个方法是生成代理类的字节数组,待会将在测试类里直接调用,看看代理类文件到底长什么样子。
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
这个方法根据类加载器,代理类名,代理类文件返回动态代理类
defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);

看看我们生成的代理文件

public class ProxyTest {
    public static void main(String[] args) {
        NewsService service = new NewsServiceImpl();
        generatorProxyFile(service);
    }

    public static void generatorProxyFile(NewsService service) {
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy.1", service.getClass().getInterfaces());
        FileOutputStream out = null;
        try {
            out = new FileOutputStream("$Proxy.1.class");
            out.write(classFile);
            out.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

为了看起来简洁一些我把异常处理删掉


public final class 2 extends Proxy
  implements NewsService
{
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m4;
  private static Method m2;

  public 2(InvocationHandler paramInvocationHandler) {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject) {
   return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }

  public final void add(){
      this.h.invoke(this, m3, null);
      return;
  }

  public final int hashCode(){
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
  }

  public final void del(){ 
      this.h.invoke(this, m4, null);
      return;
  }

  public final String toString() {
      return (String)this.h.invoke(this, m2, null);
  }

  static
  {

      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("test.NewsService").getMethod("add", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m4 = Class.forName("test.NewsService").getMethod("del", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
}

这里我们看到了我们的add del 方法都变成了有h.invode(….);
h就是我们MyInvocatioHandler对象。
构造函数里传入了一个InvocationHandler类型的参数,

 public 2(InvocationHandler paramInvocationHandler) {
    super(paramInvocationHandler);
  }

看到这里,我们就应该想到之前的一行代码:

return cons.newInstance(new Object[]{h});

所以执行代理对象的add方法 实际上执行的是MyInvocatioHandler.invoke(proxy,add,args);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值