天天看點

aop 面向切面之代理類分析

spring-aop(面向切面程式設計)

為什麼需要aop(面向切面程式設計)?

如果沒有aop,那隻能用oop(面向對象程式設計),也就是用封裝,繼承,多态三大特性進行程式設計。可以把oop看成是縱向式的程式設計。 如下圖

上圖最明顯的就是代碼的重複,開啟事務和關閉事務的代碼在三個業務中會出現三次。

再看下圖

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-UyKH5T8U-1572270125366)(C:\Users\admain\Desktop\be relieved\1907\day007\02.png)]

如上圖把公用代碼抽取出來,橫向的切入我們的業務代碼中,這就是面向切面程式設計。如何實作?

靜态代理:

演藝圈中,藝人不可能一個人什麼都要管。現實中,藝人隻管表演,表演前的準備工作和表演後的後續收尾工作都由經紀人來管理。我們模拟下這個場景。

規範接口(表演),業務邏輯類(藝人表演),代理類(經紀人負責藝人表演整個過程能順利完成)

建立一個代理類,代理類依賴于一個實際完成業務邏輯的類,代理類和業務邏輯類實作同一個接口,規範這兩個類,在業務類中實作業務邏輯即可。在代理類中,調用業務類的方法,在此方法前後進行方法的加強,比如加上開啟和關閉事務的方法。

1.規範接口

package com.qfedu.jintai;
//一種表演的接口
public interface Act {
	//唱歌的表演
    public void sing();

}
           

2.業務邏輯類,實作規範

package com.qfedu.jintai;
//歌手類實作表演接口
public class Singer implements Act {
    
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
	//歌手唱歌的方法
    public void sing() {
        System.out.println(this.name + "唱歌");
    }
}
           

3.代理類,實作規範

package com.qfedu.jintai;

public class Singproxy implements Act {
	//依賴業務邏輯類
    private Singer singer;

    public Singproxy(Singer singer) {
        this.singer = singer;
    }

    //代理類實作規範方法
    public void sing() {
        //掉用業務類規範方法前的切入方法
        talk();
        //掉用業務類規範方法
        this.singer.sing();
        //掉用業務類規範方法後的切入方法
        deal();
    }

    public void talk() {
        System.out.println("談論價格");
    }

    public void deal() {
        System.out.println("交易完成");
    }


}
           

4.測試

package com.qfedu.test;

import com.qfedu.jintai.Singer;
import com.qfedu.jintai.Singproxy;
import org.junit.Test;


public class test {
    @Test
    public void test01() {
        Singer sing = new Singer("劉德華");

        Singproxy singproxy = new Singproxy(sing);
        singproxy.sing();
    }

}

           

靜态代理缺陷:每一個類如果需要被代理,都需要手動建立一個代理類,代碼又變得繁瑣。

此時,在不确定哪個類會被代理,應該調用哪個類方法,這種動态擷取屬性和動态調用方法的感覺是不是很熟悉—反射

jdk動态代理:

建立一個類實作InvocationHandler接口,并實作invoke方法,方法中有三個參數,代理對象,調用方法,調用方法的參數(三個參數都和代理對象有關),業務用法用invoke反射,再寫一個擷取代理類的方法,擷取代理類需要三個參數,分别是:需要代理類的類加載器(為生成新的一個代理類),代理類實作的接口(面向接口程式設計思想),和實作代理接口的類本身對象,傳回Object(代理類),用接口接收。用代理類調用業務方法時就會被增強。

1.規範接口

package com.qfedu.jintai;
//一種表演的接口
public interface Act {
	//唱歌的表演
    public void sing();

}
           

2.業務邏輯類,實作規範

package com.qfedu.jintai;
//歌手類實作表演接口
public class Singer implements Act {
    
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
	//歌手唱歌的方法
    public void sing() {
        System.out.println(this.name + "唱歌");
    }
}
           

3.代理類InvocationHandler接口,

package com.qfedu.JdkProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxy implements InvocationHandler {
	//和靜态代理一樣,被代理類依賴
    private Object object;
	//擷取被代理類加載器,把傳入進來的被代理類改造成一個新的代理類
    //擷取被代理類的實作接口,用于傳回接收
    //被代理類需要一個代理對象來負責代理
    public Object getInstance(Object object) {
        this.object = object;
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
    }

	//被代理類改造成一個新的代理類後,調用業務方法時,會調用此方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         //掉用業務類規範方法前的切入方法
        talk();
         //掉用業務類規範方法
        Object invoke = method.invoke(object, args);
         //掉用業務類規範方法後的切入方法
        deal();
        return invoke;

    }

    public void talk() {
        System.out.println("談論價格");
    }

    public void deal() {
        System.out.println("交易完成");
    }

}


           

4.測試

package com.qfedu.test;

import com.qfedu.JdkProxy.JdkProxy;
import com.qfedu.jintai.Act;
import com.qfedu.jintai.Singer;
import com.qfedu.jintai.Singproxy;
import com.qfedu.jintai.Act;
import org.junit.Test;

    @Test
    public void test02() {
        //後期通過依賴注入加上自動裝配實作的ioc把對象建立交給spring,代理會更加靈活,此處暫時不管
        Act song = new Singer("劉德華");
        JdkProxy jdkProxy = new JdkProxy();
        //擷取代理對象
        Act instance = (Act) jdkProxy.getInstance(song);
        instance.sing();
    }

}
           

cglib動态代理待續…

與事務相關的理論

1.事務(Transaction)的四個屬性(ACID)

原子性(Atomic) 對資料的修改要麼全部執行,要麼全部不執行。

一緻性(Consistent) 在事務執行前後,資料狀态保持一緻性。

隔離性(Isolated) 一個事務的處理不能影響另一個事務的處理。

持續性(Durable) 事務處理結束,其效果在資料庫中持久化。

2.事務并發處理可能引起的問題

髒讀(dirty read):一個事務讀取了另一個事務尚未送出的資料,

不可重複讀(non-repeatable read) :一個事務的操作導緻另一個事務前後兩次讀取到不同的資料

幻讀(phantom read) :一個事務的操作導緻另一個事務前後兩次查詢的結果資料量不同。

JDBC的事務支援

2.事務隔離級别(Transaction Isolation Levels)

JDBC提供了5種不同的事務隔離級别,在Connection中進行了定義。

JDBC定義了五種事務隔離級别:

TRANSACTION_NONE JDBC驅動不支援事務
TRANSACTION_READ_UNCOMMITTED 允許髒讀、不可重複讀和幻讀。
TRANSACTION_READ_COMMITTED 禁止髒讀,但允許不可重複讀和幻讀。
TRANSACTION_REPEATABLE_READ 禁止髒讀和不可重複讀,單運作幻讀。
TRANSACTION_SERIALIZABLE 禁止髒讀、不可重複讀和幻讀。

           

事務相關摘取https://www.cnblogs.com/lmyupupblogs/

https://www.cnblogs.com/lmyupupblogs/p/10248099.html

繼續閱讀