Aspect Oriented Programming(AOP) - The first sight

AOP 是個程式編寫方式,透過允許橫切的方式分離並且模組化,能在不修改程式碼本身就能添加額外的程式碼。接下來介紹 Spring實作的 AOP 與library AspectJ。


圖片出處 www.baeldung.com


AOP

Aspect - 標準的程式碼功能分散在分散在application中多個位置點,每個aspect專注於特定的橫切功能
Joinpoint - 程式執行過程的的特殊點,例如method 執行、call建構子、參數被指定, etc
Advice - 於在特定的joinpoint的aspect中採取行動
Pointcut - match joinpoint的正規表示法,當join point match 的pointcut, 與pointcut相關的特定advice會被直執行
Weaving - 連結aspects 與目標物件來建立advised 物件的process

Business Object - 一般的邏輯物件,像是兩個參數相加
public class SampleAdder {
public int add(int a, int b) {
return a + b;
}
}
Aspect - 能跨多個class的模組化類別
public class AdderAfterReturnAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public void afterReturn(Object returnValue) throws Throwable {
logger.info("value return was {}", returnValue);
}
}
以上就是個簡單在物件,當關聯物件return之後,會寫log。此時還沒有任何Spring annotation去做關聯。

Joinpoint - 執行程式中的連接點,例如執行method或處理exception。
在Spring AOP中,JoinPoint通常是在程式執行的時候。

Pointcut - 切入點是個predicate(謂詞是一個會回傳boolean的function),藉由Aspect的joinpoint協助match到需被執行advice 。
Advice與pointcut expression做關聯,在任何joinpoint 被pointcut match 到時Advice會被執行。

Advice - 在aspect的特定join point時,執行 的一個動作。包含 around, after, before的advice類型。
In Spring, advice是個攔截器圍繞在所有joinpoint

Wiring Business object and Aspect
<bean id="sampleAdder" class="org.baeldung.logger.SampleAdder" />
<bean id="doAfterReturningAspect"
  class="org.baeldung.logger.AdderAfterReturnAspect" />
<aop:config>
  <aop:aspect id="aspects" ref="doAfterReturningAspect">
    <aop:pointcut id="pointCutAfterReturning" expression=
      "execution(* org.baeldung.logger.SampleAdder+.*(..))"/>
    <aop:after-returning method="afterReturn"
      returning="returnValue" pointcut-ref="pointCutAfterReturning"/>
</aop:aspect>
</aop:config>
由定義得知,建立一個aop:aspect 去reference到該aspect bean。point cut設定expression去偵測程式執行business object時是否有被match到。而after-returning則是其中一種advice,當reference到的point cut,則會在business object method回傳之後去執行advice 定義的method。

更多AOP相關Annotation, 可參閱上方 Spring Bean annotation 的 Stereotype Annotation and AOP

AspectJ

除了實作AOP外更加強compile-time, post-time, and load-time weaving效能的改進。
AspectJ Runtime - 當執行AspectJ程式, class path 必須含有classes以及AspectJ runtime library jar.
AspectJWeaver - 除了AspectJ外,還需要weaver.jar引入

Aspect creation
AspectJ 實作以下三個AOP功能:
  1. Join point
  2. point cut
  3. advice

以下介紹3種如何weave accepts into code
  1. Compile-Time Weaving: 當我們有source code與aspect code,AspectJ compiler 將會把兩者進行編譯,出來的source code就能當作一般java class執行。從config 設定showWeaveInfo = true就能在執行程式時看到aspect載入狀況。
  2. Post-compile Weaving: 也可稱之為binary weaving,編織已存在的class files與jar files. config中加入jar的artifact於weaveDependencies中
  3. Load-time weaving: 直到class loader loads class file to JVM才去做weaving,由於是需要run time環境,因此需要啟動weaving agent。藉由設定aop.xml去定義 Aspects會被哪些weaving用到,以及根據不同類型weaver的執行條件等。

Annotating Aspects 範例
在aspect class上加@Aspect annotation ,用@Pointcut去指定weaving對象,用@Around這個advice於某個joinpoint,並撰寫邏輯後執行 ProceedingJoinPoint.proceed()


此外其他Annotation小知識
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Secured {
public boolean isLocked() default false;
}
以上就是定義一個@Secured的annotation,並只能在Method上加註,且提供預設為false的isLocked()參數。


兩者差異

Spring AOP and AspectJ 可以從capabilities, goals, weaving, internal structure, joinpoint, simplicity來看

Capabilities and goals

Spring AOP 實作簡單的AOP來提供跨 Spring IoC ,由於只能管理Spring Container的bean,並非是完整的AOP solution。AspectJ目標則是提供完整的AOP solution,功能強大、複雜且全面。

Weaving

Spring AOP and AspectJ各自使用不同類型的weaving行為,會影響到效能跟易用性。AspectJ的三種方式上面篇提過。AspectJ 是用compile-time 與class load time weaving,Spring AOP則是用runtime weaving。在runtime weaving,aspects在應用程式執行期間透過目標物件proxy進行weave。(JDK dynamic proxy或GCLIB proxy)

Internal Structure and Application

Spring AOP 是個proxy-based AOP framework,意味著要去透過實作interface 或繼承target object來做到與Aspect溝通。AspectJ 則直接compile去weave aspect to code。

Joinpoint

由於Spring AOP  based on proxy pattern, 因此無法處理static, final的方法,因為無法被override in runtime。
AspectJ 則是在運行之前的compile time處理完,因此target又更廣,如:method call, method execution, handler execution, etc。

Simplicity

Spring AOP 顯然是更簡單的實作方式,不必在執行過程加入額外編譯器。AspectJ因為需要額外的compiler也表示需要引入AspectJ到開發者的IDE or build tool。

Performance

compile-time 肯定是快過 runtime weaving. 


總結
Spring AOPAspectJ
Implemented in pure JavaImplemented using extensions of Java programming language
No need for separate compilation processNeeds AspectJ compiler (ajc) unless LTW is set up
Only runtime weaving is availableRuntime weaving is not available. Supports compile-time, post-compile, and load-time Weaving
Less Powerful – only supports method level weavingMore Powerful – can weave fields, methods, constructors, static initializers, final class/methods, etc…
Can only be implemented on beans managed by Spring containerCan be implemented on all domain objects
Supports only method execution pointcutsSupport all pointcuts
Proxies are created of targeted objects, and aspects are applied on these proxiesAspects are weaved directly into code before application is executed (before runtime)
Much slower than AspectJBetter Performance
Easy to learn and applyComparatively more complicated than Spring AOP




references:

留言

這個網誌中的熱門文章

[專案] 銀行端末系統

如何在MacOS 中自由切換不同Python版本 - pyenv + virtualenv

用 C# 控制 Win7 輸入法