設計模式(一)--代理模式

設計模式是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

2.1).jdk動態代理

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類實現的接口,實現對象

缺點:

  只能代理實現接口的類,若是沒有接口,將沒法使用

2.2).cglib動態代理

  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文件已經存在

  二、動態代理:程序運行過程,由反射機制動態生成

文章參考:公衆號-方誌朋-一塊兒學設計模式 - 代理模式

相關文章
相關標籤/搜索