昨天面試碰到了面試官問spring的時候,問完ioc,然後下個問題我以為是aop,後來才聽清是動態代理,感覺回答的不是太好,也是好久不接觸 1.靜態代理 代理模式也就委托模式。 三個角色: 1. Subject抽象主題角色:介面 2. RealSubject具體主題角色:介面的實現類,業務邏輯的具體 ...
昨天面試碰到了面試官問spring的時候,問完ioc,然後下個問題我以為是aop,後來才聽清是動態代理,感覺回答的不是太好,也是好久不接觸
1.靜態代理
代理模式也就委托模式。
三個角色:
1. Subject抽象主題角色:介面
2. RealSubject具體主題角色:介面的實現類,業務邏輯的具體執行者
3. Proxy代理主題角色:也叫做委托類,代理類。它負責對真實角色的應用,負責真實角色前後前後做預處理和善後處理。
在這裡面Subject是一個藉口,裡面有一個Request()方法,RealSubject類實現了Subject這個介面,並且實現了request()方法,而在Proxy也實現了Subject介面,proxy裡面還有一個變數Subject,可以通過構造函數將RealSubject註入,在實現request方法時,其實是調用的是Realsubject裡面的request方法,在調用request()方法前後可以調用一些其他的方法。
下麵是具體的代碼
Subject.java
public interface Subject { //定義一個方法 public void request(); }
RealSubject.java
public class RealSubject implements Subject { @Override public void request() { //業務邏輯處理 } }
Proxy.java
public class Proxy implements Subject { private Subject subject = null; public Proxy(Subject subject){ this.subject = subject; } @Override public void request() { before(); subject.request(); after(); } public void before(){ //do something } public void after(){ //do something } }
代理模式的使用場景
為什麼要使用代理呢?想想現實世界吧,打官司為什麼要找個律師?因為你不想參與中間過程的是是非非,只要完成自己的答辯就行了,其他的比如事前調查、事後調查都由律師搞定,這就是為了減輕你的負擔。代理模式的使用場景非常多,可以看見Spring aop,這是非常典型的動態代理
二:動態代理
動態代理是在實現階段不用關心代理誰,而在運行階段才指定代理哪一個對象。相對來說,自己寫代理類的方式就叫靜態代理
劃重點,在運行階段指定哪一個對象
具體代碼,邏輯待會再說
抽象主題
public interface Subject { /** * //業務操作 * @param str */ void doSomething(String str); /** * 吃 * */ void eat(String str); }
真實主題
public class RealSubject implements Subject { @Override public void doSomething(String str) { System.out.println("do something!---->" + str); } @Override public void eat(String str) { System.out.println("今天晚上吃"+str); } }
動態代理的handler類
public class MyInvocationHandler implements InvocationHandler { /** * 被代理的對象 */ private Object target; public MyInvocationHandler(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //log Before System.out.println("log before:"+"method: "+method.getName()+ "return :"+method.getReturnType().getSimpleName()); Object result = method.invoke(target,args); System.out.println("log after: "+new Date(System.currentTimeMillis())); return result; } }
動態代理類
public class DynamicProxy<T> { public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler){ //返回目標,並返回結果 return (T) Proxy.newProxyInstance(loader,interfaces,handler); } }
動態代理的場景類
public class Client { public static void main(String[] args) throws IOException { //定義一個代理類 Subject subject = new RealSubject(); //定義一個Handler InvocationHandler handler = new MyInvocationHandler(subject); //定義主題的代理 Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler); //代理的行為 System.out.println(proxy.getClass().getCanonicalName()); proxy.doSomething("finish"); proxy.eat("香鍋里辣家的麻辣香鍋"); //此處可以將 byte[] proxyClass = ProxyGenerator.generateProxyClass(proxy.getClass() .getSimpleName(), proxy.getClass().getInterfaces()); //將位元組碼文件保存到D盤,文件名為$Proxy0.class FileOutputStream outputStream = new FileOutputStream(new File( "d:\\$Proxy0.class")); outputStream.write(proxyClass); outputStream.flush(); outputStream.close(); } }
分析過程:
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);
在我們使用proxy.doSomthing(args);
proxy.eat(args);*
***我們可以想象出,DynamicProxy.newProxyInstance(args)這個方法返回了一個proxy對象***
我們可以看到是調用了這個方法
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
@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); } }最後這個方法會在運行中生成一個
類,名字叫:com.sun.proxy.$Proxy0
而我們並沒有找到這個類,可以通過
ProxyGenerator.generateProxyClass
將這個運行中生成的類列印出來,,我們來看看,這個類是什麼樣子的
$Proxy0.class,反編譯
public final class $Proxy0 extends Proxy implements Subject { private static Method m1; private static Method m2; private static Method m3; private static Method m4; 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 doSomething(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 void eat(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); } } 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.husky.dynamicproxy.Subject").getMethod("doSomething", Class.forName("java.lang.String")); m4 = Class.forName("com.husky.dynamicproxy.Subject").getMethod("eat", 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這個類extends Proxy implements Subject
有一個靜態代碼塊,會反射生成Method類,也就是給 $Proxy這個類的變數賦值
舉例我在調用proxy.doSomething()這個方法時
我們其實是調用
public final void doSomething(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); } }
調用的是super.h.invoke(this, m3, new Object[]{var1});
這個h也就是實現InvocationHandler介面的MyInvocationHandler類。將這個$Proxy0,m3, new Object[]{var1}這些變數傳過去
具體代碼:https://github.com/pompeii666/proxy