jdk动态代理生成代理对象源码分析-4

来源:互联网 发布:windows xp下 arp命令 编辑:程序博客网 时间:2024/05/22 06:56

在分析JdkDynamicAopProxy类中的invoke方法之前,我们先看看如何实现jdk动态代理:

1、目标类 StudentImplService.java

2、目标类所实现的接口 IStudent.java

3、日志类 LogImplService.java

4、日志类所实现的接口 ILog.java

5、代理对象生成类 MyInvocationHandler.java

6、测试类 Test_Proxy.java

 

package spring_dynamic_proxy;

public interface IStudent {

public void say(String name);

}

 

package spring_dynamic_proxy;

public class StudentImplServiceimplements IStudent{

@Override

public void say(String name) {

System.out.println("StudentImplService : " + name +" say hello world");

}

}

 

package spring_dynamic_proxy;

public interface ILog{

public void start();

public void end();

}

 

package spring_dynamic_proxy;

import java.util.Date;

public class LogImplServiceimplements ILog{

/**

 * 输出开始时间

 */

@Override

public void start() {

System.out.println("start time :" + System.currentTimeMillis());

}

/**

 * 输出结束时间

 */

@Override

public void end() {

System.out.println("ent time : " + System.currentTimeMillis());

}

}

 

package spring_dynamic_proxy;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

 

public class MyInvocationHandlerimplements InvocationHandler{

 

//调用(日志)对象

private Object obj;

//目标对象

private Object target;

public  MyInvocationHandler(Object target,Object obj){

this.target = target;

this.obj = obj;

}

public Object getProxy(){

//生成代理对象

return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),

this.target.getClass().getInterfaces(),this);

}

/**

 * 由jvm自己调用,该方法非显示调用(由动态生成的proxy对象中的invocationHandler进行回调该方法)

 */

@Override

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

throws Throwable {

Object result = null;

Object temp = proxy;

//System.out.println("proxy : " + proxy.getClass());//jvm自动生成的代理对象

//System.out.println("method : " + method.getName()); //目标(核心业务)方法名

//System.out.println("args : " +args[0].toString()); //目标方法参数

//反射得到操作者的实例(日志对象类)

Class clazz = this.obj.getClass();

//反射得到操作者的start方法

Method start = clazz.getMethod("start");

//反射执行start方法

start.invoke(this.obj);

//执行要处理的原本方法(实际目标类的方法,即为业务对象)

method.invoke(this.target, args);

//反射得到操作者的end方法(日志对象类)

Method end = clazz.getMethod("end");

//反射执行end方法

end.invoke(this.obj);

return result;

}

 

}

 

package spring_dynamic_proxy;

public class Test_Proxy {

public static void main(String[] args){

MyInvocationHandler myInvocationHandler = new MyInvocationHandler(

new StudentImplService(),new LogImplService());

IStudent studentProxy = (IStudent)

myInvocationHandler.getProxy();

studentProxy.say("jxc");

    ProxyGeneratorUtils.writeProxyClassToHardDisk("$Proxy11.class");  

}

}

 

输出结果:

 

jdk生成代理对象的主要过程中,MyInvocationHandler首先实现了InvocationHandler接口,并实现了该接口的invoke方法,同时在该invoke方法中对目标方法进行了增强处理以及目标方法的调用。

再经过public Object getProxy(){

return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),

this.target.getClass().getInterfaces(), this);

}生成代理对象,通过java API中的Proxy生成代理对象,这里的this是指InvocationHandler的接口实现类MyInvocationHandler所生成的对象,主要目的是为了让代理对象回调该类中的invoke()方法对目标对象进行增强处理。那么它是如何调用的呢?我们可以把代理对象输出到磁盘上再经过反编译就可以看到具体的代理对象。

 

根据以上测试结果,我们可以将代理对象的字节码输出到磁盘文件中,具体方法:

package spring_dynamic_proxy;

import java.io.FileOutputStream;  

import java.io.IOException;  

  

import sun.misc.*;  

public class ProxyGeneratorUtils {  

  

    /**

     * 把代理类的字节码写到硬盘上

     * @param path 保存路径

     */  

    public static void writeProxyClassToHardDisk(String path) {  

        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11",

         StudentImplService.class.getInterfaces());          

        FileOutputStream out = null;  

          

        try {  

            out = new FileOutputStream(path);  

            out.write(classFile);  

            out.flush();  

        } catch (Exception e) {  

            e.printStackTrace();  

        } finally {  

            try {  

                out.close();  

            } catch (IOException e) {  

                e.printStackTrace();  

            }  

        }  

    }  

}

 

再经过反编译软件得到如下代码:

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.lang.reflect.UndeclaredThrowableException;

import spring_dynamic_proxy.IStudent;

 

public final class $Proxy11extends Proxy implements IStudent{

  private static Method m1;

  private static Method m0;

  private static Method m3;

  private static Method m2;

 

  public $Proxy11(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 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);

    }

  }

 

  public final void say(String paramString) throws {

    try  {

      this.h.invoke(this, m3, new Object[] { paramString });

      return;

    } 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);

    }

  }

 

  Static {

    try {

      m1 = Class.forName("java.lang.Object").getMethod("equals",new Class[] { Class.forName("java.lang.Object") });

      m0 = Class.forName("java.lang.Object").getMethod("hashCode",new Class[0]);

      m3 = Class.forName("spring_dynamic_proxy.IStudent").getMethod("say",new Class[] { Class.forName("java.lang.String") });

      m2 = Class.forName("java.lang.Object").getMethod("toString",new Class[0]);

      return;

    }  catch (NoSuchMethodException localNoSuchMethodException) {

      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());

    } catch (ClassNotFoundException localClassNotFoundException) {

      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());

    }

  }

}

 

首先,在测试类中,我们通过myInvocationHandler.getProxy()可以得到代理对象,class com.sun.proxy.$Proxy0,可以自行在测试代码中添加System.out.println(studentProxy.getClass());即可得到该结果,代理对象首先会执行static代码段得到m1-4的方法,其中m3就是我们所要增强的目标方法,然后再通过构造方法将myInvocationHandler设置到父类Proxy的属性h中去,此时代理对象已经生成,再通过测试类中调用该对象中的say(),在该方法中将会回调执行myInvocationHandlerinvoke()方法对目标方法进行增强处理。到此,jdk动态代理已经执行完成。

 

原创粉丝点击