搞懂Java动态代理
来源:互联网 发布:java系统架构师面试题 编辑:程序博客网 时间:2024/06/06 06:29
代理
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。即代理对象B控制真实对象A的访问,那为什么不直接使用真实对象?有时候真实对象不便直接使用或者不能直接使用,需要对真实对象进行增强,但又不能改变真实对象属性(开闭原则),这时就需要用到代理类。
代理类主要负责为委托了(真实对象)预处理消息、过滤消息、传递消息给委托类,代理类不现实具体服务,而是利用委托类来完成服务,并将执行结果封装处理。有两种方式的代理:
- 静态代理:程序员将代理类预先创建好。
- 动态代理:代理类在程序运行过程中动态创建。
一个典型的代理模式通常有三个角色,这里称之为代理三要素:共同接口、真实对象、代理对象。
静态代理
共同接口:
public interface Sell { void add(String name); void sell(String name);}
真实对象:
public class Seller implements Sell { @Override public void add(String name) { System.out.println("add product:" + name); } @Override public void sell(String name) { System.out.println("sell product:" + name); }}
代理对象:
public class ProxySeller implements Sell { private Sell sell; public ProxySeller(Sell sell){ this.sell = sell; } @Override public void add(String name) { sell.add(name); } @Override public void sell(String name) { sell.sell(name); }}
代理对象调用,真实对象Seller被传递给了代理对象ProxySeller,代理对象在执行具体方法时通过所持用的真实对象完成调用。
public static void main(String[] args) { System.out.println("Hello World!"); Sell sell = new ProxySeller(new Seller()); sell.add("Apple"); sell.sell("Apple"); }
在处理部分对象增强功能时,静态代理还是较合适,因为其直接落脚具体对象具体方法。但有时候面对不同对象、不同方法的代理场景时,这种代理模式就不是很灵活:
- 方式一:针对不同对象,分别创建一个代理类。
- 方式二:仅用一个代理类,实现n个不同的接口,最终分类调用。
在方案一中,会重复创建逻辑相同仅引用对象不同的代理类;方案二中会造成一个代理类的无线膨胀,最终难以控制及维护。接下来,引出动态代理…
动态代理
共同接口、真实对象不变,我们构建一个代理对象调用处理程序InvocationHandler。
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class SellerInvocationHandler implements InvocationHandler { private Object delegate; public SellerInvocationHandler(Object delegate){ this.delegate = delegate; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Befor"); method.invoke(delegate,args); System.out.println("After"); return null; }}
执行动态代理:
public static void main(String[] args) { System.out.println("Hello World!"); Sell delegate = new Seller(); InvocationHandler handler = new SellerInvocationHandler(delegate); Sell proxy = (Sell)Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), handler); proxy.add("Apple"); proxy.sell("Apple");}
通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例。针对不同的代理类,传入相应的代理程序控制器InvocationHandler。如果新来一个委托类PrimaryStudent,如:
public interface Student { void buy(String name); void say(String name);}public class PrimaryStudent implements Student { @Override public void buy(String name) { System.out.println("Student Buy " + name); } @Override public void say(String name) { System.out.println("Student Say " + name); }}
实现对这个类的动态代理过程如下:
public static void main(String[] args) { System.out.println("Hello World!"); Sell delegate = new Seller(); Student student = new PrimaryStudent(); InvocationHandler handler = new SellerInvocationHandler(delegate); InvocationHandler handler1 = new SellerInvocationHandler(student); Sell proxy = (Sell)Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), handler); Student proxy1 = (Student)Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), handler1); proxy.add("Apple"); proxy.sell("Apple"); proxy1.say("Apple"); proxy1.buy("Apple"); }
其实动态代理的基本要素仍然是:1、共同接口;2、真是对象;3代理对象(只不过此时的代理类是自动生成的)。Spring AOP就是动态代理的典型实现。
道理差不多明白了,接下来继续了解动态代理底层的过程,及代理类如何生成的…
底层过程
newProxyInstance方法究竟是如何生成一个代理实例的,通过其源码展开说明:
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
整体流程:
- 1、生成代理类Proxy的Class对象。
- 2、如果Class作用域为私有,通过 setAccessible 支持访问
- 3、获取Proxy Class构造函数,创建Proxy代理实例。
其中,利用getProxyClass0(loader, intfs)生成代理类Proxy的Class对象,其源码如下,其中有说明,如果指定接口的代理类已经存在与缓存中,则不用新创建,直接从缓存中取即可;如果缓存中没有指定代理对象,则通过ProxyClassFactory来创建一个代理对象。
/** * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); }
ProxyClassFactory内部类创建、定义代理类,返回给定ClassLoader 和interfaces的代理类。其中核心方法就是apply,
/** * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.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, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } } }
proxyClassFile是生产的代理类字节码,generateProxyClass是真正生成代理类class字节码的函数,进去ProxyGenerator类的静态方法generateProxyClass。
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; }
字节码生成后,调用defineClass0来解析字节码,生成了Proxy的Class对象。在了解完代理类动态生成过程后,生产的代理类是怎样的,谁来执行这个代理类。
ProxyGenerator.generateProxyClass函数中注意下面一点:
if(saveGeneratedFiles) { ... FileOutputStream file = new FileOutputStream(dotToSlash(name) + ".class"); file.write(classFile); ... }
saveGeneratedFiles定义如下,其指代是否保存生成的代理类class文件,默认false不保存。
private static final boolean saveGeneratedFiles = ((Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();
但是为了加深理解,我们可以在main函数中修改此系统变量,main中定义了2个真实对象Sell及Student,接下来看看其生成的代理对象。
public static void main(String[] args) { System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); Sell delegate = new Seller(); Student student = new PrimaryStudent(); InvocationHandler handler = new SellerInvocationHandler(delegate); InvocationHandler handler1 = new SellerInvocationHandler(student); Sell proxy = (Sell)Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), handler); Student proxy1 = (Student)Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), handler1); proxy.add("Apple"); proxy.sell("Apple"); proxy1.say("Apple"); proxy1.buy("Apple"); }
如图,生成了两个名为 $Proxy0.class、$Proxy1.class的class文件,利用idea的反编译能力,打开两文件,其内容如下:
package com.sun.proxy;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 Sell { private static Method m1; private static Method m2; private static Method m4; private static Method m3; private static Method m0; //这个是$Proxy0继承Proxy并调用了父类的构造方法 public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //实现接口Sell的代理方法sell public final void sell(String var1) throws { try { super.h.invoke(this, m4, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } //实现接口Sell的代理方法add public final void add(String var1) throws { try { super.h.invoke(this, m3, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final int hashCode() throws { try { return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m4 = Class.forName("Sell").getMethod("sell", Class.forName("java.lang.String")); m3 = Class.forName("Sell").getMethod("add", Class.forName("java.lang.String")); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }}
$Proxy0继承了Proxy类,实现了Sell接口,是Sell对象的代理类。生成的代理类调用委托类方法时,调用InvocationHandler的invoke方法。
总结
其实,动态代理实现思路与静态代理一样,也是“共同接口、真实对象、代理对象”,只不过静态代理的代理对象是程序员预先写好的,而动态代理的代理对象是利用字节码手段动态生成代理对象的,减少了重复劳动,所以优秀的程序员可能也是一个“懒惰”的程序员。
- 搞懂Java动态代理
- 一篇文章彻底搞懂java动态代理的实现
- Java 代理,动态代理
- [Java] Java 动态代理
- java代理及动态代理
- java代理模式--动态代理
- Java静态代理、动态代理
- Java 代理之 动态代理
- Java 代理与动态代理
- java静态代理,动态代理
- 代理模式&java动态代理
- Java代理与动态代理
- Java静态代理动态代理
- JAVA代理模式--动态代理
- java 代理和动态代理
- JAVA动态代理 代理模式
- Java动态代理--jdk代理
- Java动态代理--cglib代理
- 我的App全栈之路(2)数据库设计
- 我的站点尝试
- Android开发基础之Dialog对话框大全
- android app前后台判断
- 在 Qt5中ROS开发(一)
- 搞懂Java动态代理
- 算法第十八周作业01
- CRC校验
- 在vue2中使用ajax
- 利用htmlparser爬虫获取指定完整的完整区域信息
- Kafka的简单介绍
- Mac OS X上安装 Ruby运行环境
- jquery validation Engine表单验证
- 每周荐书:MyBatis、并行编程、Ansible(评论送书)