java 动态代理原理详解

来源:互联网 发布:wince软件下载 编辑:程序博客网 时间:2024/06/18 17:40
一,具体实现接口
package proxy_pattern.move_proxy_sun;
public interface Ticket {
public void getTicket();
}
二、具体实现类
package proxy_pattern.move_proxy_sun;
public class TicketImpl implements Ticket {
 @Override
 public void getTicket() {
  System.out.println("开始买票");
 }
}
三、创建InvocationHandler实现类 
package proxy_pattern.move_proxy_sun;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTicket implements InvocationHandler {
public Object obj;
 public ProxyTicket(Object obj) {
 
 this.obj = obj;
}
 
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  System.out.println(proxy.getClass().getName());
  System.out.println(method.getName());
  System.out.println("代理之前");
  method.invoke(obj, args);
  System.out.println("代理之后");
  return null;
 }
}


四、主函数
Ticket obj = new TicketImpl();
  InvocationHandler invocation = new ProxyTicket(obj);
  Ticket t = (Ticket) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), invocation);
  t.getTicket(); 

原理说明:
 通过调用 Proxy.newProxyInstance()方法,用来生成Proxy0类,这个类其实也是实现了Ticket接口的动态生成的类,当我们调用t.getTicket()方法的时候,其实我们调用的是Proxy0类里面的 getTicket()方法,这个方法的里面又开始调用了实现了InvocationHandler接口的ProxyTicket对象的public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 这个方法,这个方法又调用了TicketImpl里面的getTicket()方法;

具体步骤如下:
一、调用Proxy.newProxyInstance方法
      1、调用Class cl = getProxyClass(loader, interfaces);方法返回Proxy0类
          getProxyClass方法如下步骤:
          1,)byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);调用这个方式生成一个实现了Ticket接口的Proxy0类字节码数据,
          2,)  proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);把字节数据生成一个Class
     2、生成的Proxy0的源代码如下,通过这个类我们可以看到它继承了 Proxy 同时也实现了 Ticket接口,在getTicket()方法里面调用了
super.h.invoke(this, m3, null);

// Decompiled by DJ v3.7.7.81 Copyright 2004 Atanas Neshkov  Date: 2013/2/4 17:29:40
// Home Page : http://members.fortunecity.com/neshkov/dj.html  - Check often for new version!
// Decompiler options: packimports(3)
import java.lang.reflect.*;
import proxy_pattern.move_proxy_sun.Ticket;
public final class ProxySubject extends Proxy
    implements Ticket
{
    public ProxySubject(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }
    public final boolean equals(Object obj)
    {
        try
        {
            return ((Boolean)super.h.invoke(this, m1, new Object[] {
                obj
            })).booleanValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    public final void getTicket()
    {
        try
        {
            super.h.invoke(this, m3, null);
            return;
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    public final int hashCode()
    {
        try
        {
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    public final String toString()
    {
        try
        {
            return (String)super.h.invoke(this, m2, null);
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    private static Method m1;
    private static Method m3;
    private static Method m0;
    private static Method m2;
    static
    {
        try
        {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                Class.forName("java.lang.Object")
            });
            m3 = Class.forName("proxy_pattern.move_proxy_sun.Ticket").getMethod("getTicket", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
        }
        catch(NoSuchMethodException nosuchmethodexception)
        {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        }
        catch(ClassNotFoundException classnotfoundexception)
        {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}


3、Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); 

动过反射生成一个对象,然后把InvocationHandler类型的ProxyTicket类注入到Proxy0的类里面,当调用Proxy0的 getTicket()方法的时候就会调用super.h.invoke(this, m3, null);这个方法,那么super.h.invoke()这个方法就是调用了InvocationHandler接口的ProxyTicket类,那么ProxyTicket里面的invoke()方法就会通过method.invoke(obj, args);反射的机制来调用这个方法,那么具体的被代理对象就会被执行

要是不明白method.invoke(obj, args)这个方法的意思可以做如下一个例子
Method method=Ticket.class.getMethods()[0];
   method.invoke(obj, null);
你会发现这个方法就执行了,Method这个是通过反射来生成的接口方法。
原创粉丝点击