Aspectj 實現Method條件運行


  最近我花了半個小時實現了一個Method的按自定義條件運行的pluginCondition-Run 。實現場景是由於我所工作的客戶經常會是在同一個代碼集上實現多個Brand,所以有些功能只會限制是幾個brand調用,而其他的調用則不該調用。還有因為持續交互,我們會不停的release新的功能得到快速的反饋,在這前提下我們會經常遇見在我們剛開發完一個brand的產品代碼,就要面臨release,所以我們希望其不該對其他的brand產生影響。

  面對這樣的需求初級程序員有些人肯定會覺得沒什么了不起的啊,不就是幾個if/else或者switch/case。我和我的團隊對代碼有一種天生的潔癖,對於太多復雜的if/elseswitch/case,以及將來會被移除的臨時非產品代碼分布在各處,有一種抵觸心理。

對於有一定工作經驗的程序員來說這樣的需求肯定也不是什么問題,不就是AOP(面向切面編程),對,這就是我們所期望的解決方案,把處理的邏輯集中,和產品代碼的分離。

知道了用AOP,也許你只對了一半,在AOP的世界里,有兩種實現方式靜態植入和動態代理,最早了AOP實現采用的是靜態植入,然后由於IOC之類的框架的興起,動態代理的實現方式也逐漸興起,取代了靜態植入的方式。但並不是說靜態植入的方式就不再有用武之地的,在這里我們所采用的AOP框架Aspectj就是一個靜態注入的框架,我們並沒有和spring結合,動態代理的方式有個基本的問題就是你不能直接new這個對象這需要交給框架處理,如果是spring框架的話,這要求你必須是一個springbean,以及動態代理會有一些性能的損失。這對於該場景的限制太多,並不是我所期望的。

靜態植入的框架在我以前的博客中也提到不少,如果感興趣請移步 《IOC/AOP隨筆目錄》。在java世界里Aspectj.net世界里PostSharp(博客中靜態植入原理分析篇《MSBuild + MSILInect實現編譯時AOP之預覽》)就是這類框架。

   回到主題,對於 condition-run如何使用請移步github文檔

這里簡述如何實現:

1 對於AOP第一步是匹配規則,所以定義一個標記:

@Retention(RUNTIME)

@Target({METHOD})

public @interface ConditionRun {

Class<? extends Runner> value();

}

 

其指向一個實現Runner接口的類型。

2:有了匹配規則,我們就可以找到切入點進行AOP邏輯的處理,

 

@Aspect

public class ConditionRunAspect {


@Around("methodsToBeConditionRun(conditionRun)")

public Object profile(ProceedingJoinPoint pjp, ConditionRun conditionRun) throws Throwable {

final Result result = isExec(pjp, conditionRun);

if (result.isExec()) {

return pjp.proceed();

}

return result.getDefaultValue();

}


private Result isExec(ProceedingJoinPoint pjp, ConditionRun conditionRun) {

try {

final Runner runner = conditionRun.value().newInstance();

final MethodSignature signature = (MethodSignature) pjp.getSignature();

return runner.exec(signature, pjp.getArgs());

} catch (Exception e) {

throw new RuntimeException("Runner must be empty constructor and make sure the config is ok.", e);

}

}


@Pointcut(value = "@annotation(conditionRun)")

public void methodsToBeConditionRun(ConditionRun conditionRun) {

}

}

 

  這里在切入方法調用之前,new了一個配置的Runner類型(注意必須午餐構造),並調用其exec方法獲取是否運行該方法,如果不運行則返回什么默認值。

Runner runner = conditionRun.value().newInstance();

final MethodSignature signature = (MethodSignature) pjp.getSignature();

return runner.exec(signature, pjp.getArgs());

 

exec的參數簽名為方法簽名信息和方法運行時參數。

    一切都這么簡單,現在你可以任意的框架Runner去做適合你的場景業務了。可以參照項目下得sample實例,該實例展示了一個當出入參數為3的時候執行,部位3則返回默認值1.

   想想還有那些場景,你是否遇見過某類單元測試我只希望運行在某種固定的場景下?假設在開發圖形應用的時候,我們希望調用一些不同平台的特定api,雖然我們代碼設計封裝做得很好,但是我們希望有固定的集成測試去cover這部分邏輯,讓我們的測試只運行是固定平台。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM