設計模式是java基礎中很重要的一部分,設計模式說白了就是之前的人總結出的套路,就像小說中那些武功祕籍、內功心法同樣java
設計模式分爲三大類:node
一、建立型模式(5種):工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式設計模式
二、結構型模式(7種):適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式數組
三、行爲型模式(11種):策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式框架
、中介者模式、解釋器模式ide
設計模式不該該死記硬背、更應該去融會貫通,應用到項目中,能夠經過查看框架或者一些優秀開源項目獲得啓發性能
本文講的是代理模式,由於要寫關於AOP的隨筆了,代理是跳不過去的,因此仍是單獨寫一下吧,方便本身理解、複習測試
生活中有不少代理的例子,不少職業都會有代理(微商、保險等),又或者是一個明星,他的經紀人也是代理,雖然這個代理有時很坑爹。this
。。又或者是Spring AOP,代理是一種思想,不僅是存在Javaspa
定義:給某一個對象提供一個代理,並由代理對象控制對原對象的引用
SellCar.java爲共同接口
public interface SellCar { void sellCar(); }
SellCarImpl.java目標對象
public class SellCarImpl implements SellCar{ @Override public void sellCar() { System.out.println("selll car"); } }
SellCarProxy.java代理類
public class SellCarProxy implements SellCar{ private SellCar sellCar; @Override public void sellCar() { System.out.println("sell car proxy start"); if (null == sellCar) { sellCar = new SellCarImpl(); } sellCar.sellCar(); System.out.println("sell car proxy end"); } }
SellCarTest.java測試類
public class SellCarTest { public static void main(String[] args) { SellCar sellCar = new SellCarProxy(); sellCar.sellCar(); } }
結果:
sell car proxy start
selll car
sell car proxy end
缺點:
目標對象要建立好,做爲代理類的內部屬性。一個target對應一個proxy,這樣若是須要代理的對象不少,難道就要寫不少proxy嗎?接口內
方法修改了,target對象和proxy對象都要修改。若是咱們提早不知道目標對象是什麼,這個都是靜態代理存在的問題
二、動態代理
動態代理不關心target對象,而是在運行期間生成proxy
jdk自帶的,不須要第三方jar包,使用簡單但相對功能較弱
SellCarProxy.java
@AllArgsConstructor //生成全參構造器 public class SellCarProxy implements InvocationHandler { private Object target; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("sell car proxy start"); Object o = method.invoke(target, args); System.out.println("sell car proxy end"); return o; } }
SellCarTest.java
public class SellCarTest { public static void main(String[] args) { SellCar sellCar = (SellCar) Proxy.newProxyInstance( SellCarImpl.class.getClassLoader(), SellCarImpl.class.getInterfaces(), new SellCarProxy(new SellCarImpl()) ); sellCar.sellCar(); } }
結果:
sell car proxy start
selll car
sell car proxy end
注意:
第一/二個參數,必定是target類,而不是通用接口類,不然會報錯:com.sun.proxy.$Proxy0 cannot be cast to com.it.SellCar,由於你
能去獲取接口的interface數組啊
三個參數分別爲:加載target的類加載器,target類實現的接口,實現對象
缺點:
只能代理實現接口的類,若是沒有接口,將沒法使用
CGLib採用了很是底層的字節碼技術,整體性能比JDK自帶的動態代理好,且功能十分強大其原理是經過字節碼技術爲一個類建立子類,並在子
類中採用方法攔截的技術攔截全部父類方法的調用,順勢織入橫切邏輯。
首先須要引入jar包
<dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>3.1</version> </dependency>
SellCarProxy.java
public class SellCarProxy implements MethodInterceptor { private Object target; public Object getTarget(Object object) { this.target = object; Enhancer enhancer = new Enhancer(); //設置父類,被代理類(這裏是Car.class) enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); // 回調方法 return enhancer.create(); // 建立代理對象 } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("sell car proxy start"); methodProxy.invokeSuper(o, objects); //代理類調用父類的方法 System.out.println("sell car proxy end"); return null; } }
SellCarTest.java
public class SellCarTest { public static void main(String[] args) { SellCarProxy proxy = new SellCarProxy(); SellCar sellCar = (SellCarImpl)proxy.getTarget(new SellCarImpl()); sellCar.sellCar(); } }
結果:
sell car proxy start
selll car
sell car proxy end
2.3).ASM:這個不太懂,實現動態代理效率很高
靜態代理和動態代理的區別:
代理類的建立時間不一樣,靜態代理一般只能代理一個類,而動態代理能夠代理多個,運行的時候才知道代理的是什麼
一、靜態代理:是直接建立的代碼,對其進行編譯。代理類的class文件已經存在
二、動態代理:程序運行過程,由反射機制動態生成
文章參考:公衆號-方誌朋-一塊兒學設計模式 - 代理模式