版本一
试着只去看API,根据自己的理解,写出了Java动态代理的第一个版本
publicclass DynamicProxyTest { publicstaticinterface IWorker { public String work(); }
publicstaticclass Worker implements IWorker{ public String work() { System.out.println("working..."); return"hello, work"; } }
publicstaticclass Invocator implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before work..."); String s = (String)method.invoke(proxy); System.out.println("after work..."); returns; } } publicstaticvoid main(String[] args) { InvocationHandler invocator = new Invocator(); IWorker proxyWorker = (IWorker)Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), new Class[]{IWorker.class}, invocator); System.out.println(proxyWorker.work()); } } |
在不知道具体怎么使用动态代理的情况下,主要围绕Proxy.newProxyInstance这个方法猜测用法的。这个方法接收三个参数,如下:
ClassLoader loader:这个好办,把当前类加载器传入即可。
Class<?>[] interfaces:生成的代理类有哪些方法,是通过传入哪些接口类决定的(这也表明了java动态代理是基于接口的);这个参数也没有疑问,直接把我们要代理的接口传入即可:new Class[]{IWorker.class}。
InvocationHandler h:实际上在实现InvocationHandler的时候不太清楚怎么实现,主要是不清楚接口中的Object proxy代表什么,于是写成了下面的样子;直接new了一个该实现类当参数传入了。
publicstaticclass Invocator implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before work..."); String s = (String)method.invoke(proxy); System.out.println("after work..."); returns; } } |
不出所料,挂掉了,而且错误信息根本停不下来啊。
想了一下,最有可能出问题的地方是:不太清楚InvocationHandler接口中接口方法invoke(Object proxy, Method method, Object[] args)中,参数proxy究竟是一个什么对象呢?
看Proxy.newProxyInstance的源代码(SUN JDK):
第一步:
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, interfaces);
生成代理类的字节码,具体怎么生成的先不管。
第二步:
/** parameter types of a proxy class constructor */
privatefinalstatic Class[] constructorParams =
{ InvocationHandler.class };
final Constructor<?> cons = cl.getConstructor(constructorParams);
获取代理类的构造函数类(构造函数在JVM中使用Constructor类表示)。
第三部:
cons.newInstance(new Object[] {h} );
构造函数+构造函数参数生成代理类实例,一个我们需要的代理类就生成的。
现在关于生成的代理类,有以下几点可以确定:
1、代理类以一个InvocationHander实例为参数,该实例是通过Proxy.newProxyInstance传入的。
2、代理类具有它所代理的接口的所有方法,比如,Iworker的代理类,就一定会有一个work()方法,因为我们将来还要通过代理类调用work()方法的。
所以,IWorker生成的代理类大体长这样:
/** * 模仿JDK动态生成的代理类 * Java为IWorker生成的代理类,应该类似我们这里实现的该类。 * 只不过JDK使用字节码技术动态生成该类,因此灵活性更高。 * @author Grucee */ publicstaticclass ImitationProxy implements IWorker{ private InvocationHandler handler; public ImitationProxy(InvocationHandler handler) { this.handler = handler; }
@Override public String work() { returnnull; }
} |
那么它的work方法又是怎么实现呢,结合InvocationHandler的接口,该方法应该是知己调用InvocationHandler的invoke方法:
public String work() { return handler.invoke(this, method, args); } |
上面的代码是编译不通过的,因为我们看似无法获取到method,args参数。其实不然,代理类怎么知道自己是有哪些方法要实现的,肯定是通过Proxy.newProxyInstance第二个参数(接口类数组),然后通过Class:getDeclaredMethods()获取到有哪些方法要实现,所以它在生成代理类的work方法的时候,肯定就知道它是Iworker.class. getDeclaredMethods[]中的work方法了;当然也就知道这个方法有哪些参数了。
至此,我们终于搞清楚了InvocationHandler:invoke(Object proxy, Method method, Object[] args)中,参数proxy代表什么?它代码的是JDK动态生成的代理类的一个实例。
再思考一个问题,动态生成的代理类会干活么?不会,只有我们自己的IWorker实现类Worker才知道work方法要做什么,所以我们必须要有一个Worker实例才能真正完成工作。因此有了下面的版本二。
版本二
publicclass DynamicProxyTest { publicstaticinterface IWorker { public String work(); }
publicstaticclass Worker implements IWorker{ public String work() { System.out.println("working..."); return"hello, work"; } }
publicstaticclass Invocator implements InvocationHandler { private IWorker worker; public Invocator(IWorker worker) { this.worker = worker; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before work..."); String s = (String)method.invoke(worker); System.out.println("after work..."); returns; } } publicstaticvoid main(String[] args) { IWorker worker = new Worker(); InvocationHandler invocator = new Invocator(worker); IWorker proxyWorker = (IWorker)Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), new Class[]{IWorker.class}, invocator); System.out.println(proxyWorker.work()); } } |
我们让InvocationHandler持有一个Worker实例,有实例、又有实例的方法,通过反射就可以完成具体的工作了。并且它可以在做具体工作前、后做任意的处理。
版本三
从上面版本二可以看出,要获取一个接口的代理类,我们要提供两个参数:接口类和实现类的一个实例。
如果接口类和实现类的包名再加一些约束条件,即通过接口类可以知道实现类的约束条件,那样我们就可以传入一个接口类,就可以返回一个代理类了。比如最简单的约束条件:接口类和实现类在同一包名下,接口类以IXXX命名,实现类以XXXImpl命名。
publicclass DynamicProxyTest { publicstaticinterface IWorker { public String work(); }
publicstaticclass IWorkerImpl implements IWorker{ public String work() { System.out.println("working..."); return"hello, work"; } }
publicstaticclass Invocator implements InvocationHandler { private Object o; private Invocator(Object o) { this.o = o; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before work..."); String s = (String)method.invoke(o); System.out.println("after work..."); returns; } }
publicstatic Object getProxy(Class<?> iface) throws Exception { String ifaceName = iface.getName(); String[] ifaceSplitted = ifaceName.split("[.]");
String packageName = ""; intlastSplit = ifaceName.lastIndexOf("."); if (lastSplit != -1) { packageName = ifaceName.substring(0, lastSplit); }
String className = ifaceSplitted[ifaceSplitted.length - 1] + "Impl"; if (!packageName.equals("")) { className = packageName + "." + className; }
//实例化实现类 Object o = Class.forName(className).newInstance(); InvocationHandler invocator = new Invocator(o); return Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), new Class[]{iface}, invocator); }
publicstaticvoid main(String[] args) throws Exception { IWorker worker = (IWorker)getProxy(IWorker.class); worker.work(); }
/** * 模仿JDK动态生成的代理类 * Java为IWorker生成的代理类,应该类似我们这里实现的该类。 * 只不过JDK使用字节码技术动态生成该类,因此灵活性更高。 * @author Grucee */ publicstaticclass ImitationProxy implements IWorker{ private InvocationHandler handler;
public ImitationProxy(InvocationHandler handler) { this.handler = handler; }
@Override public String work() { /** * Object proxy:这个好办,传入this * Method method:代理类怎么知道自己是有哪些方法要实现的,肯定是通过 * Proxy.newProxyInstance第二个参数(接口类数组),然后通过 * Class:getDeclaredMethods()获取到有哪些方法要实现,所以它在生成代理类的work方法 * 的时候,肯定是知道Method是哪个了。 * Object[] args:方法的参数 */ //return handler.invoke(this, method, args); return""; }
} } |
相关推荐
### JAVA类加载机制与动态代理 #### 一、类加载机制 ##### 1.1 类加载的时机 类加载机制负责将描述类的数据从`.class`文件加载到内存,并进行必要的校验、转换解析和初始化,使之成为可以被Java虚拟机直接使用的...
实际开发中,应深入研究每一步的实现细节,理解动态代理类的加载和生成过程,以及如何通过自定义InvocationHandler来控制方法调用的流程。同时,应该考虑如何正确处理方法调用中可能出现的异常情况,保证程序的健壮...
动态代理和静态代理是代理模式的两种主要实现方式,它们在Java编程中尤为常见。 首先,让我们从静态代理开始。静态代理是手动创建的代理类,它通常与被代理类位于同一个包下,并且实现相同的接口。在这个过程中,...
在Java中,代理模式有静态代理和动态代理两种实现方式。 首先,我们来详细了解一下静态代理。在静态代理中,我们需要创建一个代理类,这个代理类与目标类实现相同的接口,代理类在调用目标类方法的同时,可以添加...
CGLIB(Code Generation Library)是另一个常用的动态代理库,尤其适用于Java代理目标类没有实现接口的情况。CGLIB通过生成目标类的子类来创建代理对象。 **实现步骤**: 1. 引入CGLIB库。 2. 创建一个实现了`...
在Java编程领域,JDK动态代理是实现动态创建代理对象的一种技术,它是Java标准库提供的一种强大工具。Spring AOP(面向切面编程)则是一种流行的应用框架,它利用动态代理来实现对业务代码的切面增强,如日志、事务...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
最后一步是使用代理类来控制真实主题类的行为。在主程序中,我们创建真实主题类和代理类的实例,并通过代理类调用真实主题类的方法。 **代码示例:** ```java public class Main { public static void main...
在Java中,JDK提供了对动态代理的支持,允许我们在运行时创建符合指定接口的新类。这种新类(代理类)可以拦截对被代理对象的方法调用,并在调用前后执行自定义的操作,如日志记录、性能监控等。\n\n1. 静态代理与...
4. **生成动态代理对象并使用**:最后一步是使用`Proxy`类创建动态代理对象,并调用其方法。 ```java UserManager userManager = new UserManagerIml(); InvocationHandler ih = new UserShiWuHand(userManager);...
Java反射是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。...无论是进行元编程、动态代理还是框架开发,理解并掌握Java反射都是提高Java开发能力的重要一步。
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...