相比於靜態代理,動態代理避免了開發人員編寫各個繁鎖的靜態代理類,只需簡單地指定一組接口及目標類對象就能動態的得到代理對象。html
一、定義一個接口:java
package com.zze.service; public interface IWaiter { void service(); }
二、定義它的實現類:數據庫
package com.zze.service.impl; import com.zze.service.IWaiter; public class Waiter implements IWaiter { public void service(){ System.out.println("正在服務"); } }
三、使用 JDK 提供的動態代理:數組
@Test public void test() { IWaiter waiter = new Waiter(); Class<?>[] interfaces = Waiter.class.getInterfaces(); IWaiter waiterProxy = (IWaiter) Proxy.newProxyInstance(Waiter.class.getClassLoader(), interfaces, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; if (method.getName().equalsIgnoreCase("service")) { System.out.println("服務以前"); obj = method.invoke(waiter, args); System.out.println("服務以後"); } return obj; } }); waiterProxy.service(); /* 服務以前 正在服務 服務以後 */ }
JDK 動態代理只能爲實現了接口的類產生代理對象。app
從 newProxyInstance 方法看起:ide
1 @CallerSensitive 2 public static Object newProxyInstance(ClassLoader loader, 3 Class<?>[] interfaces, 4 InvocationHandler h) 5 throws IllegalArgumentException 6 { 7 Objects.requireNonNull(h); 8 9 final Class<?>[] intfs = interfaces.clone(); 10 final SecurityManager sm = System.getSecurityManager(); 11 if (sm != null) { 12 checkProxyAccess(Reflection.getCallerClass(), loader, intfs); 13 } 14 15 /* 16 * 生成代理類的 class 文件 17 */ 18 Class<?> cl = getProxyClass0(loader, intfs); 19 20 21 try { 22 if (sm != null) { 23 checkNewProxyPermission(Reflection.getCallerClass(), cl); 24 } 25 /* 26 * 獲取代理類構造函數 27 */ 28 final Constructor<?> cons = cl.getConstructor(constructorParams); 29 final InvocationHandler ih = h; 30 if (!Modifier.isPublic(cl.getModifiers())) { 31 AccessController.doPrivileged(new PrivilegedAction<Void>() { 32 public Void run() { 33 cons.setAccessible(true); 34 return null; 35 } 36 }); 37 } 38 /* 39 使用代理類的構造器,傳入參數 h(即咱們實現的InvocationHandler類實例)建立代理類的實例並返回 40 */ 41 return cons.newInstance(new Object[]{h}); 42 } catch (IllegalAccessException|InstantiationException e) { 43 throw new InternalError(e.toString(), e); 44 } catch (InvocationTargetException e) { 45 Throwable t = e.getCause(); 46 if (t instanceof RuntimeException) { 47 throw (RuntimeException) t; 48 } else { 49 throw new InternalError(t.toString(), t); 50 } 51 } catch (NoSuchMethodException e) { 52 throw new InternalError(e.toString(), e); 53 } 54 }
該方法的返回值是第 41 行返回的代理類實例,而這個代理類字節碼文件建立工做都是在 18 行的 getProxyClass0 方法完成:函數
1 private static Class<?> getProxyClass0(ClassLoader loader, 2 3 // 若是被代理類實現的接口超出 65535 個則拋出異常 4 if (interfaces.length > 65535) { 5 throw new IllegalArgumentException("interface limit exceeded"); 6 } 7 return proxyClassCache.get(loader, interfaces); 8 }
接着查看第 7 行 proxyClassCache.get 方法:源碼分析
1 public V get(K key, P parameter) { 2 Objects.requireNonNull(parameter); 3 4 expungeStaleEntries(); 5 6 Object cacheKey = CacheKey.valueOf(key, refQueue); 7 8 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); 9 if (valuesMap == null) { 10 ConcurrentMap<Object, Supplier<V>> oldValuesMap 11 = map.putIfAbsent(cacheKey, 12 valuesMap = new ConcurrentHashMap<>()); 13 if (oldValuesMap != null) { 14 valuesMap = oldValuesMap; 15 } 16 } 17 18 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); 19 Supplier<V> supplier = valuesMap.get(subKey); 20 Factory factory = null; 21 22 while (true) { 23 if (supplier != null) { 24 V value = supplier.get(); 25 if (value != null) { 26 return value; 27 } 28 } 29 30 if (factory == null) { 31 factory = new Factory(key, parameter, subKey, valuesMap); 32 } 33 34 if (supplier == null) { 35 supplier = valuesMap.putIfAbsent(subKey, factory); 36 if (supplier == null) { 37 supplier = factory; 38 } 39 } else { 40 if (valuesMap.replace(subKey, supplier, factory)) { 41 supplier = factory; 42 } else { 43 supplier = valuesMap.get(subKey); 44 } 45 } 46 } 47 }
直接從 22 行開始看,入眼就是一個死循環,它的出口在 26 行,當 supplier.get() 不爲空時返回它的值,而 supplier 的賦值操做是在第 34-38 行,賦值後就會執行 22 行 supplier.get 方法:性能
1 @Override 2 public synchronized V get() { 3 Supplier<V> supplier = valuesMap.get(subKey); 4 if (supplier != this) { 5 return null; 6 } 7 8 V value = null; 9 try { 10 value = Objects.requireNonNull(valueFactory.apply(key, parameter)); 11 } finally { 12 if (value == null) { 13 valuesMap.remove(subKey, this); 14 } 15 } 16 17 assert value != null; 18 19 CacheValue<V> cacheValue = new CacheValue<>(value); 20 21 22 if (valuesMap.replace(subKey, this, cacheValue)) { 23 24 reverseMap.put(cacheValue, Boolean.TRUE); 25 } else { 26 throw new AssertionError("Should not reach here"); 27 } 28 return value; 29 }
這個方法的返回值在第 10 行,它的值爲 valueFactory.apply(key, parameter) 的返回值,而此時 valueFactory 是 java.lang.reflect.Proxy.ProxyClassFactory 的實例,查看該實例的 apply 方法:ui
1 @Override 2 public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { 3 4 Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); 5 for (Class<?> intf : interfaces) { 6 Class<?> interfaceClass = null; 7 try { 8 interfaceClass = Class.forName(intf.getName(), false, loader); 9 } catch (ClassNotFoundException e) { 10 } 11 if (interfaceClass != intf) { 12 throw new IllegalArgumentException( 13 intf + " is not visible from class loader"); 14 } 15 16 if (!interfaceClass.isInterface()) { 17 throw new IllegalArgumentException( 18 interfaceClass.getName() + " is not an interface"); 19 } 20 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { 21 throw new IllegalArgumentException( 22 "repeated interface: " + interfaceClass.getName()); 23 } 24 } 25 26 String proxyPkg = null; 27 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; 28 29 for (Class<?> intf : interfaces) { 30 int flags = intf.getModifiers(); 31 if (!Modifier.isPublic(flags)) { 32 accessFlags = Modifier.FINAL; 33 String name = intf.getName(); 34 int n = name.lastIndexOf('.'); 35 String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); 36 if (proxyPkg == null) { 37 proxyPkg = pkg; 38 } else if (!pkg.equals(proxyPkg)) { 39 throw new IllegalArgumentException( 40 "non-public interfaces from different packages"); 41 } 42 } 43 } 44 45 if (proxyPkg == null) { 46 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; 47 } 48 49 long num = nextUniqueNumber.getAndIncrement(); 50 String proxyName = proxyPkg + proxyClassNamePrefix + num; 51 52 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( 53 proxyName, interfaces, accessFlags); 54 try { 55 return defineClass0(loader, proxyName, 56 proxyClassFile, 0, proxyClassFile.length); 57 } catch (ClassFormatError e) { 58 throw new IllegalArgumentException(e.toString()); 59 } 60 }
從 26-47 行實際上就是在拼接代理類包名,保存在變量 proxyPkg 中,在 50 行拼接出代理類全路徑。
此處 52 行的 ProxyGenerator.generateProxyClass 方法纔是真正生成代理類字節碼文件的地方,將其保存在名爲 proxyClassFile 的字節數組中。查看 ProxyGenerator.generateProxyClass 方法:
1 public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) { 2 ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); 3 final byte[] var4 = var3.generateClassFile(); 4 if (saveGeneratedFiles) { 5 AccessController.doPrivileged(new PrivilegedAction<Void>() { 6 public Void run() { 7 try { 8 int var1 = var0.lastIndexOf(46); 9 Path var2; 10 if (var1 > 0) { 11 Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar)); 12 Files.createDirectories(var3); 13 var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class"); 14 } else { 15 var2 = Paths.get(var0 + ".class"); 16 } 17 18 Files.write(var2, var4, new OpenOption[0]); 19 return null; 20 } catch (IOException var4x) { 21 throw new InternalError("I/O exception saving generated file: " + var4x); 22 } 23 } 24 }); 25 } 26 27 return var4; 28 }
在第 3 行經過 generateClassFile 方法建立代理類字節碼文件,保存在字節數組。查看 generateClassFile 方法:
1 private byte[] generateClassFile() { 2 this.addProxyMethod(hashCodeMethod, Object.class); 3 this.addProxyMethod(equalsMethod, Object.class); 4 this.addProxyMethod(toStringMethod, Object.class); 5 Class[] var1 = this.interfaces; 6 int var2 = var1.length; 7 8 int var3; 9 Class var4; 10 for(var3 = 0; var3 < var2; ++var3) { 11 var4 = var1[var3]; 12 Method[] var5 = var4.getMethods(); 13 int var6 = var5.length; 14 15 for(int var7 = 0; var7 < var6; ++var7) { 16 Method var8 = var5[var7]; 17 this.addProxyMethod(var8, var4); 18 } 19 } 20 21 Iterator var11 = this.proxyMethods.values().iterator(); 22 23 List var12; 24 while(var11.hasNext()) { 25 var12 = (List)var11.next(); 26 checkReturnTypes(var12); 27 } 28 29 Iterator var15; 30 try { 31 this.methods.add(this.generateConstructor()); 32 var11 = this.proxyMethods.values().iterator(); 33 34 while(var11.hasNext()) { 35 var12 = (List)var11.next(); 36 var15 = var12.iterator(); 37 38 while(var15.hasNext()) { 39 ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next(); 40 this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10)); 41 this.methods.add(var16.generateMethod()); 42 } 43 } 44 45 this.methods.add(this.generateStaticInitializer()); 46 } catch (IOException var10) { 47 throw new InternalError("unexpected I/O Exception", var10); 48 } 49 50 if (this.methods.size() > 65535) { 51 throw new IllegalArgumentException("method limit exceeded"); 52 } else if (this.fields.size() > 65535) { 53 throw new IllegalArgumentException("field limit exceeded"); 54 } else { 55 this.cp.getClass(dotToSlash(this.className)); 56 this.cp.getClass("java/lang/reflect/Proxy"); 57 var1 = this.interfaces; 58 var2 = var1.length; 59 60 for(var3 = 0; var3 < var2; ++var3) { 61 var4 = var1[var3]; 62 this.cp.getClass(dotToSlash(var4.getName())); 63 } 64 65 this.cp.setReadOnly(); 66 ByteArrayOutputStream var13 = new ByteArrayOutputStream(); 67 DataOutputStream var14 = new DataOutputStream(var13); 68 69 try { 70 var14.writeInt(-889275714); 71 var14.writeShort(0); 72 var14.writeShort(49); 73 this.cp.write(var14); 74 var14.writeShort(this.accessFlags); 75 var14.writeShort(this.cp.getClass(dotToSlash(this.className))); 76 var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy")); 77 var14.writeShort(this.interfaces.length); 78 Class[] var17 = this.interfaces; 79 int var18 = var17.length; 80 81 for(int var19 = 0; var19 < var18; ++var19) { 82 Class var22 = var17[var19]; 83 var14.writeShort(this.cp.getClass(dotToSlash(var22.getName()))); 84 } 85 86 var14.writeShort(this.fields.size()); 87 var15 = this.fields.iterator(); 88 89 while(var15.hasNext()) { 90 ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next(); 91 var20.write(var14); 92 } 93 94 var14.writeShort(this.methods.size()); 95 var15 = this.methods.iterator(); 96 97 while(var15.hasNext()) { 98 ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next(); 99 var21.write(var14); 100 } 101 102 var14.writeShort(0); 103 return var13.toByteArray(); 104 } catch (IOException var9) { 105 throw new InternalError("unexpected I/O Exception", var9); 106 } 107 } 108 }
在起始 2-4 行能夠看到,它還幫咱們額外的代理了 hashCode、equals、toString 方法。
接着看 sun.misc.ProxyGenerator.generateProxyClass 的第 4 行,條件 saveGeneratedFiles 是一個布爾值,用於指定是否執行下面代碼塊的保存 class 文件到硬盤的功能,默認是 false。而 saveGeneratedFiles 的值其實是取自
private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
因此咱們只要指定了它爲 true,它就會幫咱們保存字節碼文件。
在 src 根目錄下運行如下代碼:
import com.zze.dao.impl.Waiter; import com.zze.service.IWaiter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); IWaiter waiter = new Waiter(); Class<?>[] interfaces = Waiter.class.getInterfaces(); IWaiter waiterProxy = (IWaiter) Proxy.newProxyInstance(Waiter.class.getClassLoader(), interfaces, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; if (method.getName().equalsIgnoreCase("service")) { System.out.println("服務以前"); obj = method.invoke(waiter, args); System.out.println("服務以後"); } return obj; } }); waiterProxy.service(); } }
接着在項目根目錄下就會生成以下文件:
package com.sun.proxy; import com.zze.service.IWaiter; 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 IWaiter { private static Method m1; private static Method m2; private static Method m3; private static Method m0; 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}); } 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); } } public final void service() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } 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"); m3 = Class.forName("com.zze.service.IWaiter").getMethod("service"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
咱們最後使用的代理對象就是 com.sun.proxy.$Proxy0 類的實例。
CGLIB(Code Generation Library) 是一個開源項目!它是一個強大的,高性能,高質量的 Code 生成類庫,它能夠在運行期擴展 Java 類與實現 Java 接口。Hibernate 支持它來實現 PO(Persistent Object 持久化對象) 字節碼的動態生成。
一、引入 cglib 支持 jar,點擊下載。
二、編寫被代理類:
package com.zze.service; public class Waiter { public void service() { System.out.println("正在服務"); } }
三、使用 CGLIB 提供的動態代理:
@Test public void test() {// 建立核心類對象 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Waiter.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 判斷方法是不是 save if ("service".equals(method.getName())) { // 加強,權限校驗 System.out.println("權限校驗..."); } return methodProxy.invokeSuper(o, args); } }); Waiter customerDaoProxy = (Waiter) enhancer.create(); customerDaoProxy.service(); }