1.1 設計模式:前人總結的一套解決特定問題的代碼.java
1.2 代理設計模式優勢:
1.2.1 保護真實對象
1.2.2 讓真實對象職責更明確
1.2.3 利於擴展
1.3. 代理設計模式三要素
1.3.1 真實對象(老總)spring
1.3.2 代理對象(祕書)設計模式
1.3.3 抽象對象(抽象功能) ide
如下是代理模式的一個需求:this
假設咱們如今須要實現一個功能:你須要去找老總約個時間吃飯。那麼無代理的狀況就是,你到了公司,看到老總那麼直接就約吃飯。spa
那麼什麼是代理呢,就是如今公司多了一個前臺的祕書,你沒辦法直接找到老總了,你必須先和祕書說,祕書幫你和老闆約吃飯。這個過程就是代理。設計
2 靜態代理 由代理對象代理全部真實對象的功能.
2.1 本身編寫代理類
2.2 每一個代理的功能須要單獨編寫
2.3 靜態代理設計模式的缺點:
2.3.1 當代理功能比較多時,代理類中方法須要寫不少.代理
2.4 靜態代理代碼code
首先咱們須要定義個功能類,也就是抽象的接口對象
package com.suncl.proxy; public interface Gongneng{ //制定一個小目標 void zhidingxiaomubiao(); //吃飯 void chifan(); }
而後咱們須要定義一個真實的被代理對象,去完成真實須要作的動做。這裏就是老總,須要真實的完成吃飯的動做。
package com.suncl.proxy; public class Laozong implements Gongneng { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Laozong(String name) { super(); this.name = name; } public Laozong() { super(); } public void zhidingxiaomubiao(){ System.out.println("制定小目標"); } @Override public void chifan() { System.out.println("老總吃飯"); } }
以後就是最重點的代理類,也就是祕書了。首先須要實現功能類的接口,而且組合一個真實的代理對象。當調用祕書的代理類接口的時候,祕書再調用真實代理對象的代理方法,完成代理操做。
package com.suncl.proxy; public class MiShu implements Gongneng{ private Laozong laozong = new Laozong("云云"); @Override public void zhidingxiaomubiao() { System.out.println("約定時間"); laozong.zhidingxiaomubiao(); System.out.println("把訪客信息備註"); } @Override public void chifan() { System.out.println("約定時間"); laozong.chifan(); System.out.println("把訪客信息備註"); } }
而後使用的時候就只須要訪問祕書這個代理類就能夠完成和老總的吃飯動做了,這就是靜態代理模式。
package com.suncl.proxy; public class Women { public static void main(String[] args) { //找祕書 MiShu mishu = new MiShu(); //約定製定小目標 mishu.zhidingxiaomubiao(); //約定吃飯 mishu.chifan(); } }
這裏擴展下靜態代理的弊端,就是代理的目標每多一個方法,那麼接口和代理類相應的都須要多一個方法。以後的代碼我又擴展了一個運動的方法,那麼代理類就須要多一個運動的代理實現。很不方便。
3 動態代理-jdk
3.1和 cglib 動態代理對比
3.1.1 優勢:jdk 自帶,不須要額外導入 jar
3.1.2 缺點:
3.1.2.1 真實對象必須實現接口
3.1.2.2 利用反射機制.效率不高
動態代理的源碼:
第一個功能類,抽象接口
package com.suncl.jdkProxy; public interface Gongneng { void chifan(); void mubiao(); void yundong(); }
第二個是真實實現類,老總
package com.suncl.jdkProxy; public class Laozong implements Gongneng{ @Override public void chifan() { System.out.println("吃飯"); } @Override public void mubiao() { System.out.println("目標"); } @Override public void yundong() { System.out.println("老總運動"); } }
第三個就是代理類了,這裏的代理類就不須要實現接口了。主要須要實現InvocationHandle ,以後實現invoke方法就能夠了。
package com.suncl.jdkProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * Created by SCL-PC on 2019/3/3. */ public class DynamicProxyHandler implements InvocationHandler { Laozong laozong = new Laozong(); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("預定時間"); Object result = method.invoke(laozong, args); System.out.println("記錄訪客信息"); return result; } }
使用類,使用的時候使用Proxy.newProxyInstance就能夠完成基於JDK的動態代理。
import java.lang.reflect.Proxy; public class Women { public static void main(String[] args) { //第一個參數:反射時使用的類加載器 //第二個參數:Proxy須要實現什麼接口 //第三個參數:經過接口對象調用方法時,須要調用哪一個類的invoke方法 Gongneng gongneng = (Gongneng) Proxy.newProxyInstance(Women.class.getClassLoader(), new Class[]{Gongneng.class}, new DynamicProxyHandler()); gongneng.chifan(); gongneng.mubiao(); gongneng.yundong(); } }
4 動態代理-cglib
4.1cglib 優勢:
4.1.1 基於字節碼,生成真實對象的子類.
4.1.1 運行效率高於 JDK 動態代理.
4.2. cglib 缺點:
4.2.1 非 JDK 功能,須要額外導入 jar
4.3使用 spring aop 時,只要出現 Proxy 和真實對象轉換異常能夠設置<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
4.3.1 設置爲 true 使用 cglib
4.3.2 設置爲 false 使用 jdk(默認值)
cglib代碼
功能類(不變):
package com.suncl.cglibProxy; public interface Gongneng { void zhidingxiaomubiao(); void chifan(); void yundong(); }
真實實現類(不變):
package com.suncl.cglibProxy; public class Laozong implements Gongneng { @Override public void zhidingxiaomubiao() { System.out.println("目標"); } public void chifan() { System.out.println("吃飯"); } public void yundong() { System.out.println("運動"); } }
代理類:有變化須要實現 net.sf.cglib.proxy.MethodInterceptor; 並實現 intercept方法
package com.suncl.cglibProxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * Created by SCL-PC on 2019/3/3. */ public class MishuCglib implements MethodInterceptor { private Laozong laozong = new Laozong(); //至關於JDK動態代理中的綁定 public Object getInstance() { Enhancer enhancer = new Enhancer(); //建立增強器,用來建立動態代理類 enhancer.setSuperclass(laozong.getClass()); //爲增強器指定要代理的業務類(即:爲下面生成的代理類指定父類) //設置回調:對於代理類上全部方法的調用,都會調用CallBack,而Callback則須要實現intercept()方法進行攔 enhancer.setCallback(this); // 建立動態代理類對象並返回 return enhancer.create(); } // 實現回調方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("預處理——————"); proxy.invokeSuper(obj, args); //調用業務類(父類中)的方法 System.out.println("調用後操做——————"); return null; } }
代理使用(和靜態代理沒有區別):
package com.suncl.cglibProxy; import net.sf.cglib.proxy.Enhancer; public class Women { public static void main(String[] args) { MishuCglib mishuCglib = new MishuCglib(); Gongneng gongneng = (Gongneng)mishuCglib.getInstance(); gongneng.chifan(); gongneng.zhidingxiaomubiao(); gongneng.yundong(); } }
經過上述的jdk的動態代理和cglib的動態代理能夠發現,對於功能類裏面新增的新功能,代理類都不須要再新增對應的代理功能的實現了。解決了靜態代理的代理膨脹的問題。
目前代理就寫到這裏,以後會詳細研究jdk的代理實現機制和cglib的代理實現機制。
連接:https://pan.baidu.com/s/18vqlMkP5hyZPs-BvIGlk9g 提取碼:2eby