JDK 动态代理 模拟
来源:互联网 发布:有益网络怎么样 编辑:程序博客网 时间:2024/05/01 14:31
代理模式是基本的设计模式之一,它为你提供额外的或者不同的操作.jdk动态代理要对一个类进行代理,被代理的类必须实现至少一个接口.并且只有接口的方法才能被代理.
动态代理类的字节码在程序运行时由java反射机制动态生产,无需程序员手工编写它的源代码.动态代理不仅简化了编程工作,而且提供了软件的系统的可扩展性,因为java反射机制可以生成任意类型的动态代理类. 在模拟JDK动态代理之前,我们先来看看动态代理的使用.
动态代理的关键代码:
<span style="font-size:18px;">import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 实现自己的InvocationHandler * @author wanwan * */public class MyInvocationHandler implements InvocationHandler {//目标对象private Object target;/** * 构造方法 * @param target */public MyInvocationHandler(Object target) {super();this.target = target;}/** * 执行目标对象的方法 */@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//在目标对象的方法之前System.out.println("------------before-----------");Object result=method.invoke(target, args);System.out.println("------------after------------");return result;}/** * 获取目标对象的代理对象 * * @return 代理对象 */public Object getProxy(){return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(), this);}}</span>
测试代码:
<span style="font-size:18px;">@Testpublic void TestProxy() throws Throwable{//实例化目标对象UserService userService=new UserServiceImpl();//实例化InvocationHandlerMyInvocationHandler invocationHandler=new MyInvocationHandler(userService);//根据目标对象生成代理对象UserService proxy=(UserService)invocationHandler.getProxy();//调用代理对象的方法proxy.add();}</span>
测试的结果如下:
------------before-----------
-----add----------
------------after------------
这个动态代理是由JDK提供的,使用起来是比较方便的.如果要模仿JDK的动态代理,就需要了解它的内部代理是怎么样的.既然要生成代理对象,就要使用MyInvocationHandler类中的newProxyInstance方法.那么我们就来看看newProxyInstance的源代码:
<span style="font-size:18px;">public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException {if (h == null) { throw new NullPointerException();}/* * Look up or generate the designated proxy class. */Class cl = getProxyClass(loader, interfaces);/* * Invoke its constructor with the designated invocation handler. */try { Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h });} catch (NoSuchMethodException e) { throw new InternalError(e.toString());} catch (IllegalAccessException e) { throw new InternalError(e.toString());} catch (InstantiationException e) { throw new InternalError(e.toString());} catch (InvocationTargetException e) { throw new InternalError(e.toString());} }</span>
正在生成代理类class字节码的方法:ProxyGenerator,其源代码是
<span style="font-size:18px;">public static byte[] generateProxyClass(final String name, Class[] interfaces) { ProxyGenerator gen = new ProxyGenerator(name, interfaces); // 这里动态生成代理类的字节码,由于比较复杂就不进去看了 final byte[] classFile = gen.generateClassFile(); // 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上 if (saveGeneratedFiles) { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { try { FileOutputStream file = new FileOutputStream(dotToSlash(name) + ".class"); file.write(classFile); file.close(); return null; } catch (IOException e) { throw new InternalError( "I/O exception saving generated file: " + e); } } }); } // 返回代理类的字节码 return classFile; } </span>
在此处有一个关键的方法叫: getProxyClass,其源代码为:
<span style="font-size:18px;">public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)throws IllegalArgumentException {if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded");}//声明代理对象Class proxyClass = null;String[] interfaceNames = new String[interfaces.length];Set interfaceSet = new HashSet();// for detecting duplicates//遍历目标类所实现的接口for (int i = 0; i < interfaces.length; i++) { //获取接口的名称 String interfaceName = interfaces[i].getName(); Class interfaceClass = null; try {//把目标类实现的接口加载到内存中interfaceClass = Class.forName(interfaceName, false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != interfaces[i]) {throw new IllegalArgumentException( interfaces[i] + " is not visible from class loader"); } if (!interfaceClass.isInterface()) {throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } if (interfaceSet.contains(interfaceClass)) {throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } interfaceSet.add(interfaceClass); interfaceNames[i] = interfaceName;}//把目标类需要实现的接口作为缓存(Map)中的keyObject key = Arrays.asList(interfaceNames);Map cache;synchronized (loaderToCache) { //从缓存中取出cache cache = (Map) loaderToCache.get(loader); //判断缓存的内容是为空 if (cache == null) { //如果没有数据,则新建一个HashMapcache = new HashMap();//把haspMap实例和当前加载器放到缓存中loaderToCache.put(loader, cache); } }synchronized (cache) { do {Object value = cache.get(key);if (value instanceof Reference) { proxyClass = (Class) ((Reference) value).get();}if (proxyClass != null) { // proxy class already generated: return it return proxyClass;} else if (value == pendingGenerationMarker) { // proxy class being generated: wait for it try {cache.wait(); } catch (InterruptedException e) { } continue;} else { cache.put(key, pendingGenerationMarker); break;} } while (true);}try { String proxyPkg = null;// package to define proxy class in for (int i = 0; i < interfaces.length; i++) {int flags = interfaces[i].getModifiers();if (!Modifier.isPublic(flags)) { String name = interfaces[i].getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) {proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) {throw new IllegalArgumentException( "non-public interfaces from different packages"); }} } if (proxyPkg == null) {// if no non-public proxy interfaces,proxyPkg = "";// use the unnamed package } {long num;synchronized (nextUniqueNumberLock) { num = nextUniqueNumber++;}String proxyName = proxyPkg + proxyClassNamePrefix + num;byte[] proxyClassFile =ProxyGenerator.generateProxyClass( proxyName, interfaces);try { proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString());} } proxyClasses.put(proxyClass, null);} finally { synchronized (cache) {if (proxyClass != null) { cache.put(key, new WeakReference(proxyClass));} else { cache.remove(key);}cache.notifyAll(); }}return proxyClass; }</span>
<span style="font-size:18px;">public static byte[] generateProxyClass(final String name, Class[] interfaces) { ProxyGenerator gen = new ProxyGenerator(name, interfaces); // 这里动态生成代理类的字节码,由于比较复杂就不进去看了 final byte[] classFile = gen.generateClassFile(); // 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上 if (saveGeneratedFiles) { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { try { FileOutputStream file = new FileOutputStream(dotToSlash(name) + ".class"); file.write(classFile); file.close(); return null; } catch (IOException e) { throw new InternalError( "I/O exception saving generated file: " + e); } } }); } // 返回代理类的字节码 return classFile; } </span>
通过一层层的查看,对JDK提供的动态代理的方法可以说是有了一个大概的眉目了,那么就来看看模仿的JDK的源代码:
<span style="font-size:18px;">import java.io.File;import java.io.FileWriter;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.net.URL;import java.net.URLClassLoader;import javax.tools.JavaCompiler;import javax.tools.StandardJavaFileManager;import javax.tools.ToolProvider;import javax.tools.JavaCompiler.CompilationTask;public class Proxy {public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{ //JDK6 Complier API,CGLib ,ASMString methodString="";String rt = "\r\n";Method[] methods=infce.getMethods();/*for(Method m:methods){methodString +="@Override"+rt+"public void "+m.getName()+"(){"+rt+" long start = System.currentTimeMillis();" + rt +" System.out.println(\"starttime:\" + start);" + rt +" t."+m.getName()+"();" + rt +" long end = System.currentTimeMillis();" + rt +" System.out.println(\"time:\" + (end-start));" + rt +"}";}*/for(Method m : methods) {methodString += "@Override" + rt + "public void " + m.getName() + "() {" + rt + " try {" + rt + " Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + " h.invoke(this, md);" + rt + " }catch(Exception e) {e.printStackTrace();}" + rt + "}";}String src = "package com.bjsxt.proxy;" + rt +"import java.lang.reflect.Method;" + rt +"public class $Proxy1 implements " + infce.getName() + "{" + rt +" public $Proxy1(InvocationHandler h) {" + rt +" this.h = h;" + rt +" }" + rt +" com.bjsxt.proxy.InvocationHandler h;" + rt +methodString +"}";String fileName ="d:/src/com/bjsxt/proxy/$Proxy1.java";//System.getProperty("user.dir") //+ "/src/com/bjsxt/proxy/TankTimeProxy.java";File f = new File(fileName);FileWriter fw = new FileWriter(f);fw.write(src);fw.flush();fw.close();// complieJavaCompiler compiler = ToolProvider.getSystemJavaCompiler();// System.out.println(compiler.getClass().getName());StandardJavaFileManager filemgr = compiler.getStandardFileManager(null,null, null);Iterable units = filemgr.getJavaFileObjects(fileName);CompilationTask t = compiler.getTask(null, filemgr, null, null, null,units);t.call();// load into memory and create an instanceURL[] urls = new URL[] { new URL("file:/"+"d:/src/")};//+ System.getProperty("user.dir") + "/src") };URLClassLoader ul = new URLClassLoader(urls);Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1");System.out.println(c);Constructor ctr = c.getConstructor(InvocationHandler.class);Object m = ctr.newInstance(h);//m.move();return m;}}</span>运行客户端,在我的D:\src\com\bjsxt\proxy 下会有以下两个文件:
运用反编译软件,我们看看&Proxy1.class的代码:
<span style="font-size:18px;">import java.lang.reflect.Method;public class $Proxy1 implements Moveable{ InvocationHandler h; public $Proxy1(InvocationHandler paramInvocationHandler) { this.h = paramInvocationHandler; } public void move() { try { Method localMethod = Moveable.class.getMethod("move", new Class[0]); this.h.invoke(this, localMethod); } catch (Exception localException) { localException.printStackTrace(); } }}</span>看到这个代码,你是不是会想到静态代理中的proxy的代码呢?
总结:
JDK的动态代理听着挺高大尚的,但是一层层剥开它神秘的外套的时候,发现它最根本的内容还是和静态代理一样的.只是代理类不再需要我们手动书写了,有程序更加传递的接口然后自动生成了而已.所以说再难的内容最终还是要回归简单的内容的.
0 0
- JDK 动态代理 模拟
- 模拟JDK动态代理
- 模拟JDK动态代理
- 模拟JDK动态代理
- 模拟JDK动态代理实现
- 模拟实现JDK动态代理
- 模拟JDK动态代理 ; 自己动手模拟实现java动态代理
- JAVA动态代理 ps:模拟jdk
- 模拟JDK动态代理类的实现
- 模拟JDK动态代理-独立逻辑代码
- 模拟JDK动态代理(JAVA设计模式)
- 由微见著,模拟JDK动态代理的实现1
- 一个简单的例子模拟JDK动态代理
- 简单模拟Spring AOP功能 (2) JDK动态代理技术和CGLib的动态代理
- 代理模式,JDK动态代理
- Java动态代理--jdk代理
- 代理模式-JDK动态代理
- JDK中的动态代理
- yaml 4种java支持库的比较
- hdu3790最短路径问题
- 临时链接
- Bootloader - Main system - Recovery的三角关系
- 二叉排序树
- JDK 动态代理 模拟
- mtk note
- 撕裂我的头发
- 二进制、八进制、十六进制
- 上班第一天
- mysql 查询当天数据
- HDU 4135 Co-prime(容斥原理求互质数)
- VAX自动生成注释
- 一个小小的关灯游戏