Java中动态代理技术生成的类与原始类的区别 (转)

  用动态代理的时候,对它新生成的类长什么样子感到好奇.有幸通过一些资料消除了心里的疑惑.

  平时工作使用的Spring框架里面有一个AOP(面向切面)的机制,只知道它是把类重新生成了一遍,在切面上加上了后来定义的逻辑.这样就达到了动态的在原有类上增加一些功能.比如日志打印,拦截信息等.

  这里只关心动态代理技术生成新的类,先不管虚拟机是如何去生成类,用了什么字节码生成技术,怎么产生字节码等这一系列动作.现在只关心最后生成的新类长什么样,它和老类有什么区别.为了获取到生成后的代理类的字节码并且反编译成我们能够看得懂的代码,需要实现一个动态代理例子.

例子

//接口

package note.com;

/**
 * Girl接口
 * @author lxz
 *
 */
public interface IGirl {
    void sayHello();
}

//接口实现,也是需要利用动态代理扩展功能的类

package note.com;

/**
 * 具体Girl
 * @author lxz
 *
 */
public class MyGirl implements IGirl {
    public void sayHello() {
        System.out.println("如花似玉石榴姐");
    }
}

//代理实现类

package note.com;

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

/**
 * 代理类
 * 功能:给IGirl实现类增加介绍
 * @author lxz
 *
 */
public class ProxyGirl implements InvocationHandler {
    Object originalObj;

    Object bind(Object originalObj) {
        this.originalObj = originalObj;
        return Proxy.newProxyInstance(originalObj.getClass()
                .getClassLoader(), originalObj.getClass().getInterfaces(),
                this);
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("第一美女是:");
        return method.invoke(originalObj, args);
    }
}

//测试类

package note.com;

/**
 * 测试类
 *
 * @author lxz
 *
 */
public class Test {

    public static void main(String[] args) {
        IGirl hello = (IGirl) new ProxyGirl().bind(new MyGirl());
        hello.sayHello();     System.out.println(hello.getClass().getName());
    }

}

结果:

第一美女是:
如花似玉石榴姐
com.sun.proxy.$Proxy0

这里可见hello真实类型是$Proxy0,到底它长什么样子,往下看.

代理类字节码反编译结果

package note.com;

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 IGirl {

    private static Method m3;
    private static Method m1;
    private static Method m0;
    private static Method m2;

    /*
     * 构造函数传入能够访问真实对象的代理类,这个实际是上例Test中的new ProxyGirl()
     */
    protected $Proxy0(InvocationHandler h) {
        super(h);
    }

    /*
     * 代理实现sayHello,
     */
    public void sayHello() {
        try {
            this.h.invoke(this, m3, null);
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }

    }

    /*
     * 代理实现继承自Object的equals
     */
    public void equals() {
        try {
            this.h.invoke(this, m1, null);
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    /*
     * 代理实现继承自Object的hashCode
     */
    public int hashCode() {
        try {
            return (Integer) this.h.invoke(this, m0, null);
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    /*
     * 代理实现继承自Object的toString
     */
    public String toString() {
        try {
            return (String) this.h.invoke(this, m2, null);
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    /*
     * 初始化真实对象中的所有方法
     */
    static {
        try {
            m3 = Class.forName("note.com.IGirl").getMethod("sayHello",
                    new Class[0]);
            m1 = Class.forName("java.lang.Object").getMethod("equals",
                    new Class[] { Class.forName("java.lang.Object") });
            m0 =  Class.forName("java.lang.Object").getMethod("equals",
                    new Class[0]);
            m2 =  Class.forName("java.lang.Object").getMethod("equals",
                    new Class[0]);
        } catch (NoSuchMethodException localNoSuchMethodException) {
            throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        } catch (ClassNotFoundException localClassNotFoundException) {
            throw new NoClassDefFoundError(
                    localClassNotFoundException.getMessage());
        }
    }

}

  通过观察反编译后的动态类,这个逻辑并不复杂,主要功能是对所有的方法进行初始化,到执行某个方法的时候调用我们自己实现的代理类去执行扩展功能和原始类的方法.

对原始类和动态代理后产生的类进行比较:

1,$Proxy0访问真实的类对象通过InvocationHandler的实现类调用.

2,动态代理扩展功能并没有在$Proxy0中加入,而是回调InvocationHandler的接口,通过子类实现Invoke方法扩展.

从调用关系上看使用动态代理前后:

左边:是原始的调用关系,原始类中有什么逻辑就执行什么.

右边:是动态代理以后,通过动态代理生成类的对象调用代理类,代理类调用扩展逻辑,然后调用原始类对象的逻辑.由此实现了对原始类的动态扩展.

  通过这样追本溯源的去了解,我对动态代理的理解更加深刻,也打消了心里的一个疑惑.

ps:

动态代理什么时候用?可以参考这个:动态代理技术实现设计模式-代理模式

文中的字节码反编译是参考<<深入理解Java虚拟机 JVM高级特性与最佳实践>>这本书.

http://www.cnblogs.com/qinggege/p/5288182.html

时间: 2024-10-01 10:11:46

Java中动态代理技术生成的类与原始类的区别 (转)的相关文章

代理模式 &amp; Java原生动态代理技术 &amp; CGLib动态代理技术

第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务.(其实就是在代理类中关联一个委托类的实例,然后在代理类中进行包装). UML图如下: 第二部分.在Java中实现代理模式  按照代理的创建时期,代理类可以分

java中动态代理实现机制

JAVA各种动态代理实现的比较 接口 interface AddInterface{ int add(int a, int b); } interface SubInterface{ int sub(int a, int b); } 实现类 class Arithmetic implements AddInterface, SubInterface{ @Override public int sub(int a, int b) { return a-b; } @Override public i

java中动态代理

一.在java中怎样实现动态代理 1.我们要有一个接口,还要有一个接口的实现类,而这个实现类呢就是我们要代理的对象 接口: 1 package org.dynamicproxy.test; 2 3 public interface UserDao { 4 public void addUser(User user); 5 } 接口的实现类(即要代理的对象): 1 package org.dynamicproxy.test; 2 3 public class UserDaoMysqlImpl im

Java中动态代理实现原理深究

一.前言 笔者平时开发使用"动态代理"不多,最近在看设计模式的时候,"动态代理"又在面前晃了几次,所以这次想从源码的角度去分析动态代理的实现原理,以窥探其精妙~ 二.正文 2.1 静态代理  本文源码基于:jdk1.6.0_33 在正式剖析动态代理的源码之前,我们可以先来看看"静态代理"(就是我们普通的代理模式)的UML图: 从上图可以看出,代理类"ProxySubject"和被代理类"RealSubject&quo

java中动态代理的实现

动态代理的实现 使用的模式:代理模式.代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.类似租房的中介. 两种动态代理:(1)jdk动态代理,jdk动态代理是由Java内部的反射机制来实现的,目标类基于统一的接口(InvocationHandler)(2)cglib动态代理,cglib动态代理底层则是借助asm来实现的,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势. 主要应用的框架:Spring中的AOP,Struts2中的拦截器 具体实现: 1.定义接口

Java中动态代理方式:

JDK中生成代理对象的API 代理类所在包:java.lang.reflect.ProxyJDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是: static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h ) 注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为: ClassLoader loader,:指定当

Java——动态代理技术

1.程序中的代理 为具有相同接口的目标类的各个方法,添加一些系统功能,如日志,异常处理,计算方法运行的 时间,事务管理等等,都可以交给另一个类去实现这些功能,该类称为代理类. 注意:为了让代理类共享目标类中的各个方法,可以让代理类实现和目标类相同的接口. public class AProxy { //AProxy类为A的代理类,可以计算sayHi方法的运行时间 public void getTime() { //方法开始前时间 new A().sayHi(); //方法结束后时间 } } cl

java动态代理技术

主要用来做方法的增强.让你能够在不改动源代码的情况下,增强一些方法,在方法运行前后做不论什么你想做的事情(甚至根本不去运行这种方法).由于在InvocationHandler的invoke方法中,你能够直接获取正在调用方法相应的Method对象.详细应用的话.比方能够加入调用日志,做事务控制等. 另一个有趣的作用是能够用作远程调用,比方如今有Java接口,这个接口的实现部署在其他server上,在编写client代码的时候,没办法直接调用接口方法,由于接口是不能直接生成对象的,这个时候就能够考虑

Java中动态生成当前日期的文件

1.Java中动态生成当前日期的文件名称并且将控制台的输出信息输入到文件中     public static void SaveClonseToFile() throws IOException, FileNotFoundException {         File f = new File(getCurrentDateFileName() + ".txt");         f.createNewFile();         FileOutputStream fileOut