JAVA动态代理 - JDK -- 纯JAVA代码
来源:互联网 发布:淘宝内衣店铺名字大全 编辑:程序博客网 时间:2024/06/05 22:44
静态代理:编译时就已经确定了代理关系,代理类和被代理类均实现同一个接口,且代理类持有被代理类的引用。
动态代理:运行时编译确定代理关系,生成代理类,代理类持有特定的Handler类的引用,并由此特定类的引用通过反射调用被代理类的方法,在调用被代理类方法时,在被代理类方法前后插入代理类方法。
JDK动态代理:
接口:
/** * @projectName:JavaProxy * @fileName:People.java * @packageName:club.younge.proxy * @date:2016年9月4日上午11:29:44 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */ package club.younge.proxy; /** * @className:People * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月4日 上午11:29:44 * @author Younge * @version * @since JDK 1.8 * @see */public interface People {public void eat() throws Throwable;public void sleep() throws Throwable;public void sport() throws Throwable;}被代理类:
/** * @projectName:JavaProxy * @fileName:Jason.java * @packageName:club.younge.proxy * @date:2016年9月4日上午11:31:55 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */ package club.younge.proxy; /** * @className:Jason * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月4日 上午11:31:55 * @author Younge * @version * @since JDK 1.8 * @see */public class Jason implements People{@Overridepublic void eat() {System.out.println("Jason is eating now.");}@Overridepublic void sleep() {System.out.println("Jason is sleeping now.");}@Overridepublic void sport() {System.out.println("Jason is sporting now.");}}实现JDK的一个调用接口ProxyHandler:
/** * @projectName:JavaProxy * @fileName:ProxyHandler.java * @packageName:club.younge.proxy.jdk * @date:2016年9月4日上午11:34:57 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */ package club.younge.proxy.jdk;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import club.younge.proxy.People;/** * @className:ProxyHandler * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月4日 上午11:34:57 * @author Younge * @version * @since JDK 1.8 * @see */public class ProxyHandler implements InvocationHandler {private People people;public ProxyHandler(People people) {this.people = people;}@Overridepublic Object invoke(Object obj, Method method, Object[] objArray) throws Throwable {before();method.invoke(people, objArray);after();return null;}private void before(){System.out.println("Before eat you should washes hands!");}private void after(){System.out.println("After eat you should do some work!");}}
JDK动态代理测试类:
/** * @projectName:JavaProxy * @fileName:SelfTest.java * @packageName:club.younge.test * @date:2016年9月4日上午11:44:37 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */ package club.younge.test;import java.io.FileOutputStream;import java.io.IOException;import java.lang.reflect.Proxy;import club.younge.proxy.Jason;import club.younge.proxy.People;import club.younge.proxy.jdk.ProxyHandler;import sun.misc.ProxyGenerator;/** * @className:SelfTest * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月4日 上午11:44:37 * @author Younge * @version * @since JDK 1.8 * @see */public class JdkTest {public static void main(String[] args) throws Throwable {People people = (People) Proxy.newProxyInstance(People.class.getClassLoader(), new Class[]{People.class}, new ProxyHandler(new Jason()));people.eat();System.out.println("People's actual class:" + people.getClass().getName());System.out.println("Game over!");//createProxyFile();}public static void createProxyFile() throws IOException{String proxyName = "ProxyPeople";byte[] data = ProxyGenerator.generateProxyClass(proxyName, new Class[]{People.class}); //调试时的名称为$Proxy0FileOutputStream fos = new FileOutputStream(proxyName + ".class");fos.write(data);fos.close();}}测试结果:
Before eat you should washes hands!
Jason is eating now.
After eat you should do some work!
People's actual class:com.sun.proxy.$Proxy0
Game over!
从测试结果可以看出,JDK动态生成的代理类为com.sun.proxy.$Proxy0(类全名),将此动态生成的代理类的字节码输出为文件,然后通过JD-GUI反编译为java文件,代码如下:
package club.younge.proxy.jdk;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;import club.younge.proxy.People;/** * generated by jdkTest and decompiled by jd-gui. * @author Younge * */public final class ProxyPeople extends Proxy implements People {private static final long serialVersionUID = 1L;private static Method m1;private static Method m4;private static Method m2;private static Method m5;private static Method m3;private static Method m0;static {try {m1 = Class.forName("java.lang.Object").getMethod("equals",new Class[] { Class.forName("java.lang.Object") });m4 = Class.forName("club.younge.proxy.People").getMethod("eat", new Class[0]);m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);m5 = Class.forName("club.younge.proxy.People").getMethod("sport", new Class[0]);m3 = Class.forName("club.younge.proxy.People").getMethod("sleep", new Class[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);// return;} catch (NoSuchMethodException localNoSuchMethodException) {throw new NoSuchMethodError(localNoSuchMethodException.getMessage());} catch (ClassNotFoundException localClassNotFoundException) {throw new NoClassDefFoundError(localClassNotFoundException.getMessage());}}public ProxyPeople(InvocationHandler paramInvocationHandler) {super(paramInvocationHandler);}public final boolean equals(Object paramObject) {try {return ((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();} catch (Error | RuntimeException localError) {throw localError;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}public final void eat() {try {this.h.invoke(this, m4, null);return;} catch (Error | RuntimeException localError) {throw localError;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}public final String toString() {try {return (String) this.h.invoke(this, m2, null);} catch (Error | RuntimeException localError) {throw localError;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}public final void sport() {try {this.h.invoke(this, m5, null);return;} catch (Error | RuntimeException localError) {throw localError;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}public final void sleep() {try {this.h.invoke(this, m3, null);return;} catch (Error | RuntimeException localError) {throw localError;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}public final int hashCode() {try {return ((Integer) this.h.invoke(this, m0, null)).intValue();} catch (Error | RuntimeException localError) {throw localError;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}}
从反编译的代码看出,动态生成的代理类,继承JDK的Proxy类,并实现了我们自定义的People接口,并持有,我们实现的ProxyHandler类的引用。在调用代理类方法时,实则调用了ProxyHandler的invoke方法,然后在此invoke方法中,反射调用被代理类方法。最终代理类调用了被代理类的方法。
自己实现JDK的动态代理过程:
接口和被代理类如上。
我们需要手动实现JDK定义的Proxy的newProxyInstance()方法。
/** * @projectName:JavaProxy * @fileName:MyProxy.java * @packageName:club.younge.proxy.self * @date:2016年9月5日下午5:34:24 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */package club.younge.proxy.self;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import javax.tools.JavaCompiler;import javax.tools.JavaCompiler.CompilationTask;import javax.tools.StandardJavaFileManager;import javax.tools.ToolProvider;/** * @className:MyProxy * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月5日 下午5:34:24 * @author Younge * @version * @since JDK 1.8 * @see */public class MyProxy {private static String rt = "\r\n";@SuppressWarnings({ "rawtypes", "unchecked" })public static Object newProxyInstance(ClassLoader classLoader, Class interfs,MyInvocationHandler invocationHandler) {try {Method[] methods = interfs.getMethods();// 1.创建一个JAVA文件,用流的方式创建一个JAVA文件,生成JAVA文件String内容String proxyClass = "package club.younge.proxy.self;" + rt + "import java.lang.reflect.Method;" + rt+ "public class $Proxy0 implements " + interfs.getName() + "{" + rt + "MyInvocationHandler h;" + rt+ "public $Proxy0(MyInvocationHandler h) {" + rt + "this.h = h;" + rt + "}"+ getMethodStr(methods, interfs) + rt + "}";// 2.类生成文件String fileName = "E:/GitLocal/Java/JavaProxy/JavaProxy" //请务必注意文件路径是否正确,检查您的工程目录+ "/src/club/younge/proxy/self/$Proxy0.java";File file = new File(fileName);FileWriter fileWriter = new FileWriter(file);fileWriter.write(proxyClass);fileWriter.flush();fileWriter.close();// 3. 编译JAVA文件JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();StandardJavaFileManager stdFileMgr = compiler.getStandardFileManager(null, null, null);Iterable units = stdFileMgr.getJavaFileObjects(fileName);CompilationTask task = compiler.getTask(null, stdFileMgr, null, null, null, units);task.call();stdFileMgr.close();//file.delete(); //编译后可将该文件删除,造成与JDK动态代理一样的效果// 4.把class字节码加载到内存中 ////请务必注意文件路径是否正确,检查您的工程目录MyClassLoader classLoader2 = new MyClassLoader("E:/GitLocal/Java/JavaProxy/JavaProxy"+ "/src/club/younge/proxy/self/");Class proxy0Class = classLoader2.findClass("$Proxy0");Constructor constructor = proxy0Class.getConstructor(MyInvocationHandler.class);Object object = constructor.newInstance(invocationHandler);return object;} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return null;}@SuppressWarnings("rawtypes")private static String getMethodStr(Method[] methods, Class interfs) {StringBuilder builder = new StringBuilder();builder.append(rt);for (Method method : methods) {builder.append("public void ").append(method.getName()).append("() throws Throwable {").append(rt).append("Method md = ").append(interfs.getName()).append(".class.getMethod(\"").append(method.getName()).append("\", new Class[]{});").append(rt).append("this.h.invoke(this, md, null);").append(rt).append("}").append(rt);}return builder.toString();}}此方法主要做:
1.拼凑动态代理类的字符串
2.将上述字符串写入.java文件中
3.编译.java文件为class字节码,
4.将字节码文件加载到内存中
自定义invocationhandler接口及对应接口实现类和ClassLoader类:
/** * @projectName:JavaProxy * @fileName:MyInvocationHandler.java * @packageName:club.younge.proxy.self * @date:2016年9月5日下午5:30:26 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */package club.younge.proxy.self;import java.lang.reflect.Method;/** * @className:MyInvocationHandler * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月5日 下午5:30:26 * @author Younge * @version * @since JDK 1.8 * @see */public interface MyInvocationHandler {public Object invoke(Object obj, Method method, Object[] objArray) throws Throwable;}
/** * @projectName:JavaProxy * @fileName:MyProxyHandler.java * @packageName:club.younge.proxy.self * @date:2016年9月5日下午5:31:06 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */ package club.younge.proxy.self;import java.lang.reflect.Method;import club.younge.proxy.People;/** * @className:MyProxyHandler * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月5日 下午5:31:06 * @author Younge * @version * @since JDK 1.8 * @see */public class MyProxyHandler implements MyInvocationHandler{private People people;public MyProxyHandler(People people) {this.people = people;}@Overridepublic Object invoke(Object obj, Method method, Object[] objArray) throws Throwable {before();people.eat();after();return null;}private void before(){System.out.println("Before eat you should washes hands!");}private void after(){System.out.println("After eat you should do some work!");}}
/** * @projectName:JavaProxy * @fileName:MyClassLoader.java * @packageName:club.younge.proxy.self * @date:2016年9月5日下午11:35:07 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */package club.younge.proxy.self;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;/** * @className:MyClassLoader * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月5日 下午11:35:07 * @author Younge * @version * @since JDK 1.8 * @see */public class MyClassLoader extends ClassLoader {private File dir;public MyClassLoader(String path) {dir = new File(path);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {if (dir != null) {File classFile = new File(dir, name + ".class");if (classFile.exists()) {FileInputStream fis = null;try {fis = new FileInputStream(classFile);ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = fis.read(buffer)) != -1) {baos.write(buffer, 0, len);}return defineClass("club.younge.proxy.self." + name, baos.toByteArray(), 0, baos.size());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}}return super.findClass(name);}}
/** * @projectName:JavaProxy * @fileName:SelfTest.java * @packageName:club.younge.test * @date:2016年9月5日下午5:38:08 * @copyright (c) 2016, heqy@finansir.nt All Rights Reserved. * */ package club.younge.test;import club.younge.proxy.Jason;import club.younge.proxy.People;import club.younge.proxy.self.MyProxy;import club.younge.proxy.self.MyProxyHandler;/** * @className:SelfTest * @function: TODO ADD FUNCTION. * @reason: TODO ADD REASON. * @date: 2016年9月5日 下午5:38:08 * @author Younge * @version * @since JDK 1.8 * @see */public class SelfTest {public static void main(String[] args) throws Throwable {People people = (People) MyProxy.newProxyInstance(People.class.getClassLoader(), People.class, new MyProxyHandler(new Jason()));people.eat();System.out.println("Game over!");}}测试结果:
Before eat you should washes hands!
Jason is eating now.
After eat you should do some work!
Game over!
与JDK动态代理效果类似。
0 0
- JAVA动态代理 - JDK -- 纯JAVA代码
- 动态代理--java jdk
- java jdk动态代理
- Java JDK动态代理
- java jdk 动态代理
- Java JDK 动态代理
- java jdk动态代理
- Java JDK 动态代理
- Java-JDK动态代理
- java jdk动态代理
- Java动态代理--jdk代理
- java动态代理 JDK、Cglib动态代理
- Java中的动态代理--JDK动态代理
- Java动态代理之JDK动态代理
- Java 动态代理(JDK&CGLib)
- Java动态代理之JDK
- Java JDK 动态代理例子
- Java的JDK动态代理
- Robotium自动化测试之签名
- uboot的编译和链接过程分析(一)
- ES6折腾记- 箭头函数【Arrow function】要点及脱坑点
- Android中Handler机制的理解
- 每日一省之—使用线性探测法(仅利用数组作为底层数据结构)实现HashMap
- JAVA动态代理 - JDK -- 纯JAVA代码
- Ghost博客搭建步骤
- MyEclipse配置代码格式化模版
- xtml简单登录表单
- 对于struct file_operations中ioctl消失的学习笔记
- c/c++ 时间日期函数
- uboot启动内核的实现
- 【华为OJ4】字符串分隔
- 328. Odd Even Linked List