支持Spel表達式的注解(aop例子)

spring boot上支持@cacheable的緩存孔祸,其中的“key” 和“cacheNames”支持spel表達式隆敢,效果如下

spel表達式的提示

關(guān)于spel表達式是什么,大家可以自助查詢崔慧,這個是相關(guān)文檔地址:Spel

spel表達式不僅支持調(diào)用方法拂蝎,還支持調(diào)用對象里面的參數(shù),這個正是我的需求惶室,平時傳給annotation的參數(shù)都是固定的温自,但是通過Spel表達式我們可以傳一個變量值,甚至是執(zhí)行一個方法皇钞。

下面我嘗試在aop里面注入Spel表達式的實現(xiàn):

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Test{

public String id() default"";

public String text() default"";

}

使用方法:

@Test(id="#id",text="#userService.test()")

public void test(UserBase userBase, int id){

}

通過這樣的注解我是可以正常調(diào)用到userService的test方法的悼泌,這里有個值得注意的地方,test方法一定要是public的夹界,可是#id馆里,卻一直報著null的錯誤,或者是類似于這樣的錯誤

EL1008E:(pos 0): Property or field 'id' cannot be found on object of type 'java.lang.Integer' - maybe not public?

我一度懷疑是context沒有把這個id這個常量給注進去可柿,又或者我的contex獲取有誤

帶著這樣的疑惑鸠踪,一開始我找到了一個@ConditionalOnExpression的注解,它允許在Spring的EL表達式中寫一個調(diào)節(jié)复斥,在IDEA里同樣是有代碼提示的

@ConditionalOnExpression注解

但是很可惜营密,繼續(xù)源著@ConditionalOnExpression這個注解查下去并沒有太多的發(fā)現(xiàn)

這個時候,我只好查@Cacheable的實現(xiàn)目锭,看一下它的key值是如何拿出來的

因為通過調(diào)試沒辦法看出@Cacheable的是如何實現(xiàn)的评汰,我只好把@Cacheable下面的所有相關(guān)代碼大概過了一下

@Cacheable的相關(guān)代碼

結(jié)果在CacheAspectSupport的里發(fā)現(xiàn)了這個

privateObjectexecute(finalCacheOperationInvoker invoker,Method method,CacheOperationContexts contexts) {

// Special handling of synchronized invocation

if(contexts.isSynchronized()) {

CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();

if(isConditionPassing(context,CacheOperationExpressionEvaluator.NO_RESULT)) {

Object key = generateKey(context,CacheOperationExpressionEvaluator.NO_RESULT);

Cache cache = context.getCaches().iterator().next();

try{

returncache.get(key, newCallable() {

@Override

publicObjectcall()throwsException {

returninvokeOperation(invoker);

}

如上述代碼里有一個Object key = generateKey(context,CacheOperationExpressionEvaluator.NO_RESULT);

然后發(fā)現(xiàn)了這個

protectedObjectgenerateKey(Object result) {

if(StringUtils.hasText(this.metadata.operation.getKey())) {

EvaluationContext evaluationContext = createEvaluationContext(result);

return evaluator.key(this.metadata.operation.getKey(), this.methodCacheKey,evaluationContext);

}

其中evaluationContext是用來構(gòu)造context的,而evaluator.key(this.metadata.operation.getKey(), this.methodCacheKey,evaluationContext);方法是正常的從context中獲取spel表達式里的值侣集,那么我的重點就在他的context是如何獲取到的键俱,是不是和我們寫的context有什么不一樣的地方

后來,我在MethodBasedEvaluationContext的代碼里發(fā)現(xiàn)這樣一段

key的最終實現(xiàn)

目瞪口呆

世分。编振。。臭埋。踪央。。瓢阴。畅蹂。。荣恐。液斜。累贤。。少漆。臼膏。。示损。渗磅。。检访。。。。密似。。蟆盹。逾滥。寨昙。舔哪。

好吧抬驴,我之前真的以為一定是Spel提供了什么神奇的方法布持,然后我們調(diào)用的就可以了,萬萬沒想到居然是自己挨個遍歷方法的參數(shù)把數(shù)據(jù)set進context的芙委。。。。哪审。。

如果我一開始就發(fā)現(xiàn)StandardEvaluationContext有個private final Map?variables=new HashMap();我覺得我沒必要走那么多彎路,粗心了朝氓。恋日。岂膳。

好了筷屡,真相大白了毙死,提供一下具體的代碼吧

aop的實現(xiàn)

@Around("execution(@com.didi.km.commons.annotation.SendEvent * *(..)) && @annotation(test)")

public voidaround(ProceedingJoinPoint joinPoint,Test test)throwsThrowable {

StandardEvaluationContext standardEvaluationContext =new StandardEvaluationContext(joinPoint.getArgs());

standardEvaluationContext = setContextVariables(standardEvaluationContext,joinPoint);

String key = ExplUtils.generateKey(test.id(),standardEvaluationContext);

.........................

}

把方法的參數(shù)set到context中去

privateStandardEvaluationContextsetContextVariables(StandardEvaluationContext standardEvaluationContext,ProceedingJoinPoint joinPoint) {

Object[] args = joinPoint.getArgs();

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

Method targetMethod = methodSignature.getMethod();

String[] parametersName =parameterNameDiscoverer.getParameterNames(targetMethod);

if(args ==null|| args.length<=0) {

return standardEvaluationContext;

}

for(int i =0;i < args.length;i++) {

standardEvaluationContext.setVariable(parametersName[i],args[i]);

}

return standardEvaluationContext;

}

最后收尾工作

public class ExplUtils {

public staticStringgenerateKey(String key,StandardEvaluationContext context) {

BeanFactory beanFactory = SpringBeanUtils.getBeanFactory();

context.setBeanResolver(newBeanFactoryResolver(beanFactory));

ExpressionParser parser =newSpelExpressionParser();

Expression exp = parser.parseExpression(key);

String value = exp.getValue(context,String.class);

returnvalue;

}

}

這樣就可以實現(xiàn)和@Cacheable一樣支持Spel表達式的效果了

最后想吐槽一下再菊,簡書這個代碼輸入感覺有點難用秉剑,有些格式給我去掉了,還是我哪里姿勢不對??盖文?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市五续,隨后出現(xiàn)的幾起案子洒敏,更是在濱河造成了極大的恐慌,老刑警劉巖疙驾,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凶伙,死亡現(xiàn)場離奇詭異,居然都是意外死亡它碎,警方通過查閱死者的電腦和手機函荣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門显押,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人傻挂,你說我怎么就攤上這事乘碑。” “怎么了金拒?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵兽肤,是天一觀的道長。 經(jīng)常有香客問我绪抛,道長资铡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任睦疫,我火速辦了婚禮害驹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蛤育。我一直安慰自己宛官,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布瓦糕。 她就那樣靜靜地躺著底洗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咕娄。 梳的紋絲不亂的頭發(fā)上亥揖,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音圣勒,去河邊找鬼费变。 笑死,一個胖子當(dāng)著我的面吹牛圣贸,可吹牛的內(nèi)容都是我干的挚歧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吁峻,長吁一口氣:“原來是場噩夢啊……” “哼滑负!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起用含,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤矮慕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啄骇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痴鳄,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年肠缔,在試婚紗的時候發(fā)現(xiàn)自己被綠了夏跷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哼转。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖槽华,靈堂內(nèi)的尸體忽然破棺而出壹蔓,到底是詐尸還是另有隱情,我是刑警寧澤猫态,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布佣蓉,位于F島的核電站,受9級特大地震影響亲雪,放射性物質(zhì)發(fā)生泄漏勇凭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一义辕、第九天 我趴在偏房一處隱蔽的房頂上張望虾标。 院中可真熱鬧,春花似錦灌砖、人聲如沸璧函。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蘸吓。三九已至,卻和暖如春撩幽,著一層夾襖步出監(jiān)牢的瞬間库继,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工窜醉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宪萄,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓榨惰,卻偏偏與公主長得像雨膨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子读串,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)撒妈,斷路器恢暖,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,424評論 0 17
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,811評論 0 11
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法狰右,類相關(guān)的語法杰捂,內(nèi)部類的語法,繼承相關(guān)的語法棋蚌,異常的語法嫁佳,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • 《無題》 浮沉遺夢與洪流 至死不渝誓不休 我言真心與哀愁 一片赤誠照江流 他日重登鸛雀樓 表我真性與離愁 我言金錢...
    Mrj21閱讀 490評論 10 10