標籤:linked link ima 個性 default nts getname 導致 缺點
引言
我們在寫一個功能函數的時候,常常要寫入一些與功能無關的代碼,如日誌記錄、參數校正、安全和事務支援等。功能無關代碼混在函數中,會帶來一些麻煩
代理模式可以解決這個問題,關鍵功能代碼放在函數中,枝節性代碼放在代理類中
代理模式
1、作用
代理模式的作用是,為其他對象提供一種代理,在不改變介面的前提下,以控制對這個對象的訪問
2、角色
代理模式一般涉及到3個角色:抽象角色(介面)、代理角色、真實(被代理)角色
3、類型
靜態代理、動態代理(jdk代理、CGLIB代理)
靜態代理
代理類、被代理類需要實現相同的介面,或者繼承相同的父類
/** * Created by danny.yao on 2017/10/9. * 靜態代理中,代理類和被代理類需要實現此介面 */public interface IUser { public void doSomething(String thingsToDo);} /** * Created by danny.yao on 2017/10/9. * 被代理類,真實商務邏輯 */public class Danny implements IUser { public void doSomething(String thingsToDo) { System.out.println(this.getClass().getName() + "一邊唱歌一邊" + thingsToDo); }} /** * Created by danny.yao on 2017/10/9. * 代理類,被代理類作為其屬性,增強被代理類功能 */public class UserProxy implements IUser { private IUser user; public UserProxy(IUser user){ this.user = user; } // 在不改變danny行為的基礎上,增強功能 public void doSomething(String thingsToDo) { doBefore(); user.doSomething(thingsToDo); doAfter(); } private void doBefore(){ System.out.println("賴床。。。"); System.out.println("起床洗漱。。。"); System.out.println("吃早飯。。。"); System.out.println("然後。。。"); } private void doAfter(){ System.out.println("那啥之後。。。"); System.out.println("開始打王者榮耀!"); }}
測試類別
public class UserProxyTest { @Test public void testDoSomething(){ UserProxy dannyProxy = new UserProxy(new Danny()); dannyProxy.doSomething("上班!!"); }}
缺點:
- 被代理類須已經存在,而且作為代理類的內部屬性
- 每個業務類都要一個代理類,如果業務量龐大,會導致類急劇膨脹
動態代理
動態代理類的源碼是在程式運行期間,由JVM根據反射等機制動態產生的
1、jdk代理
被代理類,須實現介面;代理類,不需要實現介面
// 介面和實作類別,同靜態代理 public class DynamicProxy implements InvocationHandler { // 把靜態代理中的類引用,改為Object類型 private Object object; public DynamicProxy(Object object){ this.object = object; } // 把方法調用過程改為反射方式,不依賴介面的具體方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doBefore(); method.invoke(object, args); doAfter(); return null; } private void doBefore(){ System.out.println("那啥之前。。。"); } private void doAfter(){ System.out.println("那啥之後。。。"); } // 返回動態代理 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) public <T> T getProxy(){ return (T) Proxy.newProxyInstance( object.getClass().getClassLoader(), object.getClass().getInterfaces(), this ); }}
測試類別
public class DynamicProxyTest { @Test public void testInvoke() throws Exception { DynamicProxy dynamicProxy = new DynamicProxy(new Danny()); IUser dannyProxy = dynamicProxy.getProxy(); dannyProxy.doSomething("上班!!"); }}
缺點:
2、CGLIB代理
也叫作子類代理,它是在記憶體中構建一個子類對象,從而實現對目標對象功能的擴充。被代理類不需要實現介面
// 未實現介面的類public class Pig { public void doSomething(String thingsToDo){ System.out.println("懶洋洋地" + thingsToDo); }} public class CGLibProxy implements MethodInterceptor { public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { doBefore(); Object result = methodProxy.invokeSuper(o, args); doAfter(); return result; } // cglib 中通過加強器來建立代理 public <T> T getProxy(Class<T> tClass){ return (T) Enhancer.create(tClass, this); } private void doBefore(){ System.out.println("那啥之前。。。"); } private void doAfter(){ System.out.println("那啥之後。。。"); }}
測試類別
public class CGLibProxyTest { @Test public void testIntercept() throws Exception { CGLibProxy cgLibProxy = new CGLibProxy(); Pig pigProxy = cgLibProxy.getProxy(Pig.class); pigProxy.doSomething("思考人生。。。"); }}
缺點:
- 會攔截並封裝被代理類的所有方法,做不到方法層級的個人化攔截
參考:
https://www.zhihu.com/question/20794107
http://www.cnblogs.com/machine/archive/2013/02/21/2921345.html
http://www.cnblogs.com/cenyu/p/6289209.html
java代理模式