Gadtry-Aop, Spring Aop之外的新選擇
作者: harbby(github) email: [email protected] 日期: 2018.12
簡介
Gadtry 是一個構建於java8之上的工具庫, 涵蓋了Ioc
Aop
exec
graph
等等工具庫,幾乎涵蓋了日常開發中非常多工具類,當然它還在不斷豐富中.
Aop
在軟件業,AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。(來自百度百科)
Spring-Aop和Ioc組合可以說非常漂亮和完美, Spring-Aop中定義了非常好註解和概念,可以說是對Aop模式完美詮釋,Spring體系本身也非常全面, 但是Spring體系過於龐大
, 且現實中我們有太多的非Spring項目.
Gadtry-Aop
Gadtry-Aop是 Gadtry 1.1版本開始加入全新功能,旨在降低Aop使用難度,同時儘量小巧簡單, 提供在Spring-Aop之外的新選擇.在依賴上除了字節碼操作器javassist
外無任何依賴.
Gadtry-Aop 誕生有兩個目的:
其一是非spring項目 也能儘量獲得Spring-Aop相似Aop體驗
其二: 我非常討厭Spring-Aop 的expression 字符串表達式和一堆的註解.它難以記憶和閱讀, Gadtry-Aop 爲了簡化使用採用了鏈式(函數式)Api設計,你只需參照下demo,然後藉助ide就能預覽和使用所有功能,一切都是點點點
下載:
maven:
<dependency>
<groupId>com.github.harbby</groupId>
<artifactId>gadtry</artifactId>
<version>1.1.0</version>
</dependency>
非容器場景代理
這種場景非常多,就是你的項目中沒有使用任何Ioc容器.
舉個栗子:
T proxy = AopFactory.proxy(Class<T>)
.byInstance(instance)
.around(proxyContext -> {
String name = proxyContext.getInfo().getName();
System.out.println(name);
Object value = proxyContext.proceed();
switch (name) {
case "add":
Assert.assertEquals(true, value); //Set or List
break;
case "size":
Assert.assertTrue(value instanceof Integer);
break;
}
});
這個例子中 Class<T>
指類或接口, instance這個具體的實現類活子類實現類.這個例子中用到了 環繞通知(around)
模式. 這裏注意如果Class<T>
是接口,則默認使用jdk動態代理, 否則使用字節碼技術生成動態代理類.
我們在來看個結合Gadtry-Ioc容器例子
IocFactory iocFactory = GadTry.create(binder -> {
binder.bind(Map.class).byCreator(HashMap::new).withSingle();
binder.bind(HashSet.class).by(HashSet.class).withSingle();
}).aop(binder -> {
binder.bind("point1")
.withPackage("com.github.harbby")
//.subclassOf(Map.class)
.classAnnotated()
.classes(HashMap.class, HashSet.class)
.whereMethod(methodInfo -> methodInfo.getName().startsWith("add"))
.build()
.before((info) -> {
Assert.assertEquals("add", info.getName());
System.out.println("before1");
})
.after(() -> {
Assert.assertTrue(true);
System.out.println("after2");
});
}).initialize();
Set set = iocFactory.getInstance(HashSet.class);
這個例子中結合了Ioc容器來使用Aop, 在Spring開發中基本都是結合Ioc容器來使用的Aop的.
這個例子中我們 使用了掃包,過濾器等來定位需要被代理類和方法, 最後添加了 前置通知(before)
和後置通知(after)
基本概念
這篇文章中我們不會着重介紹IOC, 我們來重點感謝Aop的幾個概念:
-
Gadtry-Aop支持通知類型
- 前置通知(Before) 指: 在目標方法被調用之前調用通知功能。
- 後置通知(After)指: 在目標方法完成之後調用通知,無論方法正確執行與否。
- 返回通知 (after-Returning) 指: 在目標方法成功執行之後調用通知。
- 異常通知(After-throwing):在目標方法拋出異常後調用通知。
- 環繞通知(Around):通知包裹了被通知的方法,由使用者決定和調用目標方法
* 關於通知類型須知:
()->{} ,切入邏輯中無法獲取目標方法相關信息,如args[]名稱等 (info)->{info.getArgs()} , 這樣就可以獲取目標方法相關信息
- 切點(pointcut)
組成切面的最小單位, 我們通常使用明確的類和方法名稱,或是利用掃描和過濾所匹配的類和方法名稱來指定切點.
切點定義:
binder.bind("point1")
.withPackage("com.github.harbby")
//.subclassOf(Map.class)
.classAnnotated()
.classes(HashMap.class, HashSet.class)
.whereMethod(methodInfo -> methodInfo.getName().startsWith("add"))
.build()
.before((info) -> {
Assert.assertEquals("add", info.getName());
System.out.println("before1");
})
.after(() -> {
Assert.assertTrue(true);
System.out.println("after2");
});
- 切面(pointcut)
切面用來組織一組相關的切點.一個切面中可以定義多個切點
public class DemoAspect implements Aspect {
@Override
public void register(Binder binder) {
binder.bind("point1")
.classes(HashSet.class).build()
.after(() -> {
System.out.println("after");
});
binder.bind("point2")
.classes(Map.class).build()
.after(() -> {
System.out.println("after");
});
}
}
- 動態代理
Gadtry-Aop 優先使用jdk動態代理,如果遇到非接口無法代理時則使用Javassist動態字節碼技術來代理