設(shè)計(jì)模式導(dǎo)致分層—如何實(shí)現(xiàn)參數(shù)傳遞(文末附彩蛋)稠曼?

一個(gè)項(xiàng)目/模塊中形病,有時(shí)候會(huì)將生命周期劃分成:校驗(yàn)層->轉(zhuǎn)換層->持久化層->后置處理層。

這樣劃分無疑可以使得各層級(jí)職責(zé)更加明確霞幅,但是會(huì)引入一個(gè)新的問題窒朋,即參數(shù)如何傳遞?

例如:在“校驗(yàn)層”中需要通過IO查詢校驗(yàn)一個(gè)字段是否合法蝗岖,但是在“轉(zhuǎn)換層”又需要再次使用IO查詢來填充數(shù)據(jù)(“轉(zhuǎn)換層”不推薦拋出異常)。

那么為了節(jié)約性能榔至,有兩種方案:

  1. 擴(kuò)展方法入?yún)?duì)象抵赢,這種方式可以通過泛型來實(shí)現(xiàn)
  2. 通過ThreadLocal來進(jìn)行傳遞唧取。

無論哪一種方案铅鲤,都是可以解決跨層級(jí)參數(shù)傳遞的問題,但是兩種在后期的可讀性都不是很高枫弟。

那么有沒有一種方案邢享,既能保證了性能,又能保證可讀性淡诗?骇塘??

這里說一種解決方案:隱式的ThreadLocal傳遞韩容,即線程級(jí)別的緩存方案款违。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestCache {

}
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.PostConstruct;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;

/**
 *
 */
@Service
@Aspect
@Slf4j
public class RequestCacheAspect {


    private boolean openRequestCache;

    @ThreadLocalLifeCycle  //自定義注解,目的是自動(dòng)調(diào)用remove方法群凶,防止內(nèi)存泄露
    private static ThreadLocal<Map<String, Object>> requestCache = ThreadLocal.withInitial(HashMap::new);

    @PostConstruct
    public void init() {
        //可讀取啟動(dòng)參數(shù)插爹,此處也可以讀取Spring的配置參數(shù)
        openRequestCache = true;
    }


    @Around("@annotation(com.tellme.aop.RequestCache)")
    public Object doSurround(ProceedingJoinPoint point) throws Throwable {
        if (!openRequestCache) {
            return point.proceed();
        }
        MethodSignature signature = (MethodSignature) point.getSignature();

        Method method = signature.getMethod();
        Object[] args = point.getArgs();
        String methodName = method.getName();
        String className = method.getDeclaringClass().getSimpleName();

        String paramString = Stream.of(args).map(JSON::toJSONString).collect(Collectors.joining("#"));
        String cacheKey = className + "#" + methodName + "#" + paramString;
        String cacheKeyMd5 = DigestUtils.md5DigestAsHex(cacheKey.getBytes());

        if (!requestCache.get().containsKey(cacheKeyMd5)) {
            Object result = point.proceed();
            requestCache.get().putIfAbsent(cacheKeyMd5, result);
            return result;
        } else {
            return requestCache.get().get(cacheKeyMd5);
        }
    }

}

使用方式:

@Service
@Slf4j
public class RequestCacheService {


    @RequestCache
    public String test(Integer id, String name) {
        log.info("執(zhí)行test(Integer id, String name)方法啦");
        return String.join("$", id + "", name, new Date().toString());
    }

    @RequestCache
    public String test(Integer id, String name, String ex) {
        log.info("執(zhí)行test(Integer id, String name, String ex)方法啦");
        return String.join("$", id + "", name, ex, new Date().toString());
    }
}

實(shí)現(xiàn)起來是比較簡單的,即通過ThreadLocal進(jìn)行線程級(jí)別的緩存。這樣在第二次調(diào)用的時(shí)候赠尾,就會(huì)減少性能的損耗力穗,且可以跨層級(jí)的去獲取參數(shù)。

彩蛋:@ThreadLocalLifeCycle注解是如何實(shí)現(xiàn)的气嫁,詳看:http://www.reibang.com/p/494de3bf076b

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末当窗,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子杉编,更是在濱河造成了極大的恐慌超全,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邓馒,死亡現(xiàn)場離奇詭異嘶朱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)光酣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門疏遏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人救军,你說我怎么就攤上這事财异。” “怎么了唱遭?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵戳寸,是天一觀的道長。 經(jīng)常有香客問我拷泽,道長疫鹊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任司致,我火速辦了婚禮拆吆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脂矫。我一直安慰自己枣耀,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布庭再。 她就那樣靜靜地躺著捞奕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拄轻。 梳的紋絲不亂的頭發(fā)上缝彬,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音哺眯,去河邊找鬼谷浅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的一疯。 我是一名探鬼主播撼玄,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼墩邀!你這毒婦竟也來了掌猛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤眉睹,失蹤者是張志新(化名)和其女友劉穎荔茬,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竹海,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡慕蔚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了斋配。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片孔飒。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖艰争,靈堂內(nèi)的尸體忽然破棺而出坏瞄,到底是詐尸還是另有隱情,我是刑警寧澤甩卓,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布鸠匀,位于F島的核電站,受9級(jí)特大地震影響逾柿,放射性物質(zhì)發(fā)生泄漏狮崩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一鹿寻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诽凌,春花似錦毡熏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杜顺,卻和暖如春财搁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躬络。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國打工尖奔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓提茁,卻偏偏與公主長得像淹禾,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茴扁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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

  • Java面試題 GC機(jī)制 垃圾回收需要完成兩件事:找到垃圾铃岔,回收垃圾。找到垃圾一般的話有兩種方法: 引用計(jì)數(shù)法 當(dāng)...
    hackest閱讀 1,162評(píng)論 3 14
  • 寫在開頭 由于杭州的房價(jià)實(shí)在太高峭火,所以我可恥的跑路到了西安毁习。幾個(gè)月前在西安買了房,所以最近總結(jié)了一些還算全面的An...
    BlackFlag閱讀 9,821評(píng)論 10 200
  • 開門見山 我們都知道 javascript 是一種基于原型的弱類型語言卖丸,擁有動(dòng)態(tài)數(shù)據(jù)類型纺且,靈活多變。因此坯苹,相比于傳...
    Cryptic閱讀 419評(píng)論 0 5
  • java面試寶典2018 1隆檀、[ meta標(biāo)簽的作用是什么](http://www.wityx.com/post/...
    Sina華閱讀 429評(píng)論 1 2
  • 內(nèi)存模型以及分區(qū) JVM分為虛擬機(jī)棧、堆粹湃、方法區(qū)恐仑、本地方法區(qū)堆,用來存放實(shí)例化對(duì)象为鳄、非static成員變量,屬于線...
    北京黃小胖閱讀 1,217評(píng)論 0 0