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