Spring Boot中AOP結(jié)合自定義注解保存及打印請(qǐng)求日志

Spring Boot 中引入AOP(面向切面編程)尤為簡(jiǎn)單荷腊,添加AOP依賴即可女仰。AOP的作用在于分離系統(tǒng)中的各種關(guān)注點(diǎn)疾忍,將核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)分離開來(lái)一罩。更好的解耦和聂渊,提高代碼的可重用性汉嗽。結(jié)合注解就更加的靈活方便了饼暑。

實(shí)現(xiàn)步驟如下:

一、引入AOP的 pom.xml 依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

二迈着、編寫自定義注解 @Log

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {

    /**
     * 描述
     * @return
     */
    String value() default "";

    /**
     * 是否保存請(qǐng)求記錄
     */
    boolean isRecord() default false;
    

    /**
     * 是否打印返回值
     */
    boolean isWrite() default true;


}

三裕菠、定義一個(gè)切面LogAspect

//使用@Aspect注解將一個(gè)java類定義為切面類
@Aspect
@Component
public class LogAspect {

    private Logger logger = LoggerFactory.getLogger(getClass());

    //保存記錄Mapper
    @Autowired
    OperateRecordMapper operateRecordMapper;

    //使用@Pointcut定義一個(gè)切入點(diǎn),可以是一個(gè)規(guī)則表達(dá)式画髓,比如下例中某個(gè)package下的所有函數(shù),也可以是一個(gè)注解等奈虾。
    @Pointcut("@annotation(com.xiduoduo.core.annotation.Log)")
    public void log(){}

    //使用@Before在切入點(diǎn)開始處切入內(nèi)容
    @Before("log()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        //防止參數(shù)轉(zhuǎn)換報(bào)錯(cuò)
        try{
            //方法名稱
            String methodName = joinPoint.getSignature().getName();
            //方法參數(shù)
            String argsJsonStr = JSON.toJSONString(joinPoint.getArgs());
            logger.info("【"+methodName+"】開始執(zhí)行,參數(shù):"+argsJsonStr);
        }catch (Exception e){
            logger.error("日志參數(shù)轉(zhuǎn)換異常肉微,不影響業(yè)務(wù)邏輯碉纳!錯(cuò)誤信息:"+e.getMessage());
        }
    }

   //使用@AfterReturning在切入點(diǎn)return內(nèi)容之后切入內(nèi)容(可以用來(lái)對(duì)處理返回值做一些加工處理)
    @AfterReturning(returning = "ret", pointcut = "@annotation(log)")
    public void doAfterReturning(JoinPoint joinPoint, Object ret, Log log) throws Throwable {
        //防止參數(shù)轉(zhuǎn)換報(bào)錯(cuò)
        try{
            //方法名稱
            String methodName = joinPoint.getSignature().getName();
            //方法參數(shù)
            String argsJsonStr = JSON.toJSONString(joinPoint.getArgs());
            String retStr = JSON.toJSONString(ret);
            //判斷是否輸出返回值劳曹,列表數(shù)據(jù)盡量不打印
            if(log.isWrite()){
                logger.info("【"+methodName+"】執(zhí)行完畢,返回值:"+retStr);
            }else {
                logger.info("【"+methodName+"】執(zhí)行完畢");
            }
            //是否保存請(qǐng)求記錄
            if(log.isRecord()){
                OperateRecord operateRecord = new OperateRecord();
                operateRecord .setAddTime(DateUtil.getCurrentDate());
                operateRecord .setContent("[方法:"+methodName+"],[參數(shù):"+argsJsonStr+"],[返回值:"+retStr+"]");
                operateRecordMapper.insert(operateRecord );
            }
        }catch (Exception e){
            logger.error("日志參數(shù)轉(zhuǎn)換異常,不影響業(yè)務(wù)邏輯房资!錯(cuò)誤信息:"+e.getMessage());
        }
    }
}

四志膀、使用@Log注解輸出日志及保存請(qǐng)求記錄

     /**
     * 添加用戶  保存請(qǐng)求記錄熙宇,正常打印返回值
     * @param params
     * @return
     */
    @Log(isRecord = true)
    public String  addUser(String params) {
        return userService.addUser(parmas);
    }

     /**
     * 查詢所有用戶  不保存請(qǐng)求記錄,不打印返回值(列表數(shù)據(jù)過(guò)多)
     * @param params
     * @return
     */
    @Log(isWrite = false)
    public String  getUserList(String params) {
        return userService.getUserList(parmas);
    }


     /**
     * 根據(jù)用戶編號(hào)獲取用戶信息  不保存請(qǐng)求記錄溉浙,正常打印返回值
     * @param params
     * @return
     */
    @Log
    public String  getUserByUserNo(String params) {
        return userService.getUserByUserNo(parmas);
    }


其他

一烫止、AOP的相關(guān)概念

連接點(diǎn)(Joinpoint): 表示需要在程序中插入橫切關(guān)注點(diǎn)的擴(kuò)展點(diǎn),連接點(diǎn)可能是類初始化戳稽、方法執(zhí)行馆蠕、方法調(diào)用期升、字段調(diào)用或處理異常等等,Spring只支持方法執(zhí)行連接點(diǎn)互躬;在AOP中表示為“在哪里干”播赁;

切入點(diǎn)(Pointcut): 選擇一組相關(guān)連接點(diǎn)的模式,即可以認(rèn)為連接點(diǎn)的集合吼渡,Spring支持perl5正則表達(dá)式和AspectJ切入點(diǎn)模式坎背,Spring默認(rèn)使用AspectJ語(yǔ)法盒犹;在AOP中表示為“在哪里干的集合”;

通知(Advice): 在連接點(diǎn)上執(zhí)行的行為墅茉,通知提供了在AOP中需要在切入點(diǎn)所選擇的連接點(diǎn)處進(jìn)行擴(kuò)展現(xiàn)有行為的手段悍募;包括前置通知(before advice)喜鼓、后置通知(after advice)隅忿、環(huán)繞通知(around advice),在Spring中通過(guò)代理模式實(shí)現(xiàn)AOP畦娄,并通過(guò)攔截器模式以環(huán)繞連接點(diǎn)的攔截器鏈織入通知;在AOP中表示為“干什么”喂柒;

切面(Aspect):橫切關(guān)注點(diǎn)的模塊化艳吠,比如日志組件黍匾】恼铮可以認(rèn)為是通知莱褒、引入和切入點(diǎn)的組合炮障;在Spring中可以使用Schema和@AspectJ方式進(jìn)行組織實(shí)現(xiàn)智末;在AOP中表示為“在哪干和干什么集合”由蘑;

引入(Introduction): 也稱為內(nèi)部類型聲明,為已有的類添加額外新的字段或方法鹿响,Spring允許引入新的接口(必須對(duì)應(yīng)一個(gè)實(shí)現(xiàn))到所有被代理對(duì)象(目標(biāo)對(duì)象)指孤;在AOP中表示為“干什么(引入什么)”黎做;

目標(biāo)對(duì)象(Target Object):需要被織入橫切關(guān)注點(diǎn)的對(duì)象,即該對(duì)象是切入點(diǎn)選擇的對(duì)象摊溶,需要被通知的對(duì)象拉岁,從而也可稱為“被通知對(duì)象”;由于Spring AOP 通過(guò)代理模式實(shí)現(xiàn)哄啄,從而這個(gè)對(duì)象永遠(yuǎn)是被代理對(duì)象咨跌;在AOP中表示為“對(duì)誰(shuí)干”刊殉;

AOP代理(AOP Proxy): AOP框架使用代理模式創(chuàng)建的對(duì)象遍膜,從而實(shí)現(xiàn)在連接點(diǎn)處插入通知(即應(yīng)用切面)冀偶,就是通過(guò)代理來(lái)對(duì)目標(biāo)對(duì)象應(yīng)用切面。在Spring中侥猩,AOP代理可以用JDK動(dòng)態(tài)代理或CGLIB代理實(shí)現(xiàn)榔至,而通過(guò)攔截器模型應(yīng)用切面。

織入(Weaving): 織入是一個(gè)過(guò)程欺劳,是將切面應(yīng)用到目標(biāo)對(duì)象從而創(chuàng)建出AOP代理對(duì)象的過(guò)程唧取,織入可以在編譯期、類裝載期划提、運(yùn)行期進(jìn)行枫弟。組裝方面來(lái)創(chuàng)建一個(gè)被通知對(duì)象。這可以在編譯時(shí)完成(例如使用AspectJ編譯器)鹏往,也可以在運(yùn)行時(shí)完成淡诗。Spring和其他純Java AOP框架一樣,在運(yùn)行時(shí)完成織入伊履。

二韩容、注解相關(guān)概念

@Target 
說(shuō)明了Annotation所修飾的對(duì)象范圍
取值(ElementType)有:
    1.CONSTRUCTOR:用于描述構(gòu)造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部變量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述參數(shù)
    7.TYPE:用于描述類、接口(包括注解類型) 或enum聲明


@Retention
定義了該Annotation被保留的時(shí)間長(zhǎng)短:某些Annotation僅出現(xiàn)在源代碼中唐瀑,而被編譯器丟棄群凶;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會(huì)被虛擬機(jī)忽略哄辣,而另一些在class被裝載時(shí)將被讀惹肷摇(請(qǐng)注意并不影響class的執(zhí)行,因?yàn)锳nnotation與class在使用上是被分離的)柔滔。使用這個(gè)meta-Annotation可以對(duì) Annotation的“生命周期”限制溢陪。
取值(RetentionPoicy)有:
    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)

@Documented 
用于描述其它類型的annotation應(yīng)該被作為被標(biāo)注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化睛廊。Documented是一個(gè)標(biāo)記注解,沒(méi)有成員杉编。

等你年事稍長(zhǎng)超全,就會(huì)發(fā)現(xiàn)咆霜,要使世界成為一個(gè)尚可容忍的生活場(chǎng)所,首先得承認(rèn)人類的自私是不可避免的嘶朱。 -- 威廉·薩默賽特·毛姆 《人生的枷鎖》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蛾坯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子疏遏,更是在濱河造成了極大的恐慌脉课,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件财异,死亡現(xiàn)場(chǎng)離奇詭異倘零,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)戳寸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門呈驶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人疫鹊,你說(shuō)我怎么就攤上這事袖瞻。” “怎么了拆吆?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵聋迎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我枣耀,道長(zhǎng)霉晕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任奕枢,我火速辦了婚禮娄昆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缝彬。我一直安慰自己萌焰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布谷浅。 她就那樣靜靜地躺著扒俯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪一疯。 梳的紋絲不亂的頭發(fā)上撼玄,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音墩邀,去河邊找鬼掌猛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛眉睹,可吹牛的內(nèi)容都是我干的荔茬。 我是一名探鬼主播废膘,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼慕蔚!你這毒婦竟也來(lái)了丐黄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤孔飒,失蹤者是張志新(化名)和其女友劉穎灌闺,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坏瞄,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桂对,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惦积。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片接校。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狮崩,靈堂內(nèi)的尸體忽然破棺而出蛛勉,到底是詐尸還是另有隱情,我是刑警寧澤睦柴,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布诽凌,位于F島的核電站,受9級(jí)特大地震影響坦敌,放射性物質(zhì)發(fā)生泄漏侣诵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一狱窘、第九天 我趴在偏房一處隱蔽的房頂上張望杜顺。 院中可真熱鬧,春花似錦蘸炸、人聲如沸躬络。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)穷当。三九已至,卻和暖如春淹禾,著一層夾襖步出監(jiān)牢的瞬間馁菜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工铃岔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汪疮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像铲咨,于是被迫代替她去往敵國(guó)和親躲胳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蜓洪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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