面试官 | 说一下什么是代理模式?
看了這篇文章,你會對靜態代理模式,JDK 動態代理模式和 CGLIB 動態代理模式有個很清晰的認識。
01、簡介
什么是代理模式
代理模式也稱為委托模式,屬于結構型模式之一。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用,比如我們生活中的郵局,快遞公司,婚介所等等。
代理模式分類
代理模式分為靜態代理模式和動態代理模式。
靜態代理是由程序員創建或特定工具自動生成源代碼,再對其編譯。在程序運行之前,代理類.class文件就已經被創建了
動態代理是在程序運行時通過java反射機制動態創建的。
代理模式的目的
代理模式主要有兩個目的:一保護目標對象,二增強目標對象。
02、靜態代理模式
靜態代理模式的話我模擬一個古代結婚的場景。場景是這樣的:在古代,某家的公子看上了別家的姑娘,一般都是家里的大人去姑娘的家里提親,雙方父母同意了,然后就拜堂成婚,后面要宴請親朋好友。這里這個公子只需要拜堂成婚就行了,至于提親和宴請親友都是父母操辦的。我們用代碼來模擬一下這個場景。
首先我們來建個 Person 接口:
public interface Person {/*** 人有很對行為,這里我們用到的是結婚*/void marry(); }然后這家公子要成親,我們建個 Son 類實現 Person 接口:
public class Son implements Person {@Overridepublic void marry() {System.out.println("我終于結婚了");} }父親幫兒子提親,建個 Father 類:
public class Father {private Son son;public Father(Son son){this.son = son;}public void marry(){System.out.println("父親上門提親");this.son.marry();System.out.println("父親宴請親友");} }最后是測試代碼:
public class Test {public static void main(String[] args) {Father father = new Father(new Son());father.marry();} }輸出:
父親上門提親 我終于結婚了 父親宴請親友代碼寫完了,大家有沒有發現靜態代理模式的一個缺點。那就是單一,一個類只能代理一個目標對象。比如上面的場景,父親只能為自己的兒子提親,不能為別人家的孩子提親。
下面我們來看看動態代理是怎么解決這個問題的。
03、動態代理模式
動態代理模式分為 JDK 動態代理和 cglib 動態代理兩種。這里先用 JDK 動態代理的方式來模擬一個通過婚介所找朋友的場景。
先將 Person 接口改動下:
public interface Person {/*** 找朋友*/void findFriend(); }然后是婚介所 JDKMatrimonialAgency 類:
public class JDKMatrimonialAgency implements InvocationHandler {//被代理的對象,把引用給保存下來private Object target;public Object getInstance(Object target) throws Exception{this.target = target;Class<?> clazz = target.getClass();return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object obj = method.invoke(this.target,args);after();return obj;}private void before(){System.out.println("這里是婚介所,請提供你的需求");}private void after(){System.out.println("已經找到合適的,盡快安排你相親");} }JDK 動態代理主要是實現 InvocationHandler 接口,并實現 invoke 方法
然后創建 Customer 類:
public class Customer implements Person {@Overridepublic void findFriend() {System.out.println("我要找一個胸大,腿長又好看的美女");} }最后測試類:
public class Test {public static void main(String[] args) {try {Person obj = (Person)new JDKMatrimonialAgency().getInstance(new Customer());obj.findFriend();} catch (Exception e) {e.printStackTrace();}} }看下結果:
這里是婚介所,請提供你的需求 我要找一個胸大,腿長又好看的美女 已經找到合適的,盡快安排你相親然后我們用 CGLIB 來實現,如果不是spring(spring已經集成了 CGLIB )環境需要先引入 jar 包:
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version> </dependency>然后加一個 CglibMatrimonialAgency 類:
public class CglibMatrimonialAgency implements MethodInterceptor {public Object getInstance(Class<?> clazz) throws Exception{Enhancer enhancer = new Enhancer();//要把哪個設置為即將生成的新類的父類enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable {//業務的增強before();Object obj = methodProxy.invokeSuper(o,objects);after();return obj;}private void before(){System.out.println("這里是婚介所,請提供你的需求");}private void after(){System.out.println("已經找到合適的,盡快安排你相親");} }CGLIB 主要是實現 MethodInterceptor 并實現 intercept 方法。
看下結果:
這里是婚介所,請提供你的需求 我要找一個胸大,腿長又好看的美女 已經找到合適的,盡快安排你相親04、JDK和CGLIB動態代理對比
JDK 動態代理是實現了被代理對象的接口,CGLib 是繼承了被代理對象。
JDK 和 CGLib 都是在運行期生成字節碼,JDK 是直接寫 Class 字節碼,CGLib 使用 ASM框架寫 Class 字節碼,Cglib 代理實現更復雜,生成代理類比 JDK 效率低。
JDK 調用代理方法,是通過反射機制調用,CGLib 是通過 FastClass 機制直接調用方法,CGLib 執行效率更高。
05、代理模式的優缺點
優點:
降低耦合度,擴展性好
代理對象將代理對象和目標對象分離,起到保護目標對象的作用
可以對目標對象的功能增強
缺點:
增加類的數量
因為會調用增強方法,所以會造成處理速度慢
增加了系統的復雜度(這是好的架構都會有的缺點,比如spring)
近期熱文
面試珍藏:最常見的200多道Java面試題
被一個熟悉的面試題問懵了:String...
面試官:如何實現冪等性校驗?
【END】
關注下方二維碼,訂閱更多精彩內容
朕已閱?
總結
以上是生活随笔為你收集整理的面试官 | 说一下什么是代理模式?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3W字!带你玩转「消息队列」
- 下一篇: 从JDK中,我们能学到哪些设计模式?