AOP-實現(xiàn)日志管理

AOP

實現(xiàn)aop的四種方式
  • AspectJ
  • AspectWerkz
  • SpringFramework
  • JBoss

AOP核心概念

  • 1、橫切關(guān)注點
    對哪些方法進(jìn)行攔截,攔截后怎么處理呢岗,這些關(guān)注點稱之為橫切關(guān)注點
  • 2、切面(aspect)
    類是對物體特征的抽象,切面就是對橫切關(guān)注點的抽象
  • 3汉形、連接點(joinpoint)
    被攔截到的點纸镊,因為Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截到的方法获雕,實際上連接點還可以是字段或者構(gòu)造
  • 4薄腻、切入點(pointcut)
    對連接點進(jìn)行攔截的定義
  • 5、通知(advice)
    所謂通知指的就是指攔截到連接點之后要執(zhí)行的代碼届案,通知分為前置庵楷、后置、異常楣颠、最終尽纽、環(huán)繞通知五類
  • 6、目標(biāo)對象
    代理的目標(biāo)對象
  • 7童漩、織入(weave)
    將切面應(yīng)用到目標(biāo)對象并導(dǎo)致代理對象創(chuàng)建的過程
  • 8弄贿、引入(introduction)
    在不修改代碼的前提下,引入可以在運行期為類動態(tài)地添加一些方法或字段
切入點語法
  • 1.@Pointcut("下面的東西")
任何類的任何返回值的任何方法
- 1. execution(public * *(..))   

任何類的set開頭的方法
- 2.execution(* set*(..))       

任何返回值的規(guī)定類里面的方法
- 3.execution(* com.example.demo.AccountService.*(..))

任何返回值的矫膨,規(guī)定包或者規(guī)定包子包的任何類任何方法
- 4.execution(* com.example.demo.service..*.*(..)) 

  • 2.@Pointcut("@annotation(自定義注解)")

環(huán)繞通知(前置通知+執(zhí)行方法+后置通知)語法

  • @Around("logPointCut()") //@Pointcut打在哪個方法,就填哪個方法
  • @Around(execution(* com.example.demo.service...(..)))

注意:執(zhí)行方法:method(ProceedingJoinPoint joinPoint),要帶joinpoint這個參數(shù)

AspectJ

  • AspectJ是目前最完善的AOP語言
  • AspectJ是對Java編程語言的擴(kuò)展差凹,通過增加了一些新的構(gòu)造塊支持對橫切關(guān)注點的模塊化封裝,通過對源代碼級別的代碼混合實現(xiàn)織入侧馅,是一種典型的使用靜態(tài)織入的AOP實現(xiàn)機(jī)制危尿。
  • AspectJ提供了兩種橫切實現(xiàn)機(jī)制
  1. 動態(tài)橫切(DynamicCrosscutting)
  2. 另一種稱為靜態(tài)橫切(StaticCrosscutting)。
簡要api
Joinpoint
- java.lang.Object[] getArgs()/*獲取連接點方法運行時的入?yún)⒘斜?/
- Signature getSignature() /*獲取連接點的方法簽名對象*/
- java.lang.Object getTarget() //獲取連接點所在的目標(biāo)對象
- java.lang.Object getThis() //獲取代理對象本身
ProceedingJoinPoint

ProceedingJoinPoint繼承JoinPoint子接口馁痴,它新增了兩個用于執(zhí)行連接點方法的方法

//通過反射執(zhí)行目標(biāo)對象的連接點處的方法
- java.lang.Object proceed() throws Throwable
//通過反射執(zhí)行目標(biāo)對象連接點處的方法谊娇,不過使用新的入?yún)⑻鎿Q原來的入?yún)ⅰ?- java.lang.Object proceed(java.lang.Object[] args) throws Throwable

示例代碼

使用aop進(jìn)行日志管理(自定義注解方式)
自定義注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log{

    String value() default ""; //用于描述方法作用

    /**
     * 是否忽略返回值,僅方法上有效
     * @return
     */
    boolean ignoreReturn() default false;
}
切面類
/**
 * 日志切面
 */
@Aspect
//切面優(yōu)先級
@Order(100)
@Component
public class LogAspect {
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
    private static final String dateFormat = "yyyy-MM-dd HH:mm:ss";
    private static final String STRING_START = "\n--------------------------->\n";
    private static final String STRING_END = "\n<----------------------------\n";
/**
 * 切點
 */
/**
 * 不使用注解方式打切點
 *  //@Pointcut("execution (* com.example.demo.web..*(..))")")
 *  表示在使用Log注解的地方切入
 */
    @Pointcut("@annotation(Log)")
    public void logPointCut() {
    }

    //@Around("logPointCut()")---> 用于controller層
    public Object controllerAround(ProceedingJoinPoint joinPoint) {
        try {
            return printLog(joinPoint);
        } catch (Throwable throwable) {
            log.error(throwable.getMessage(), throwable);
            return true;
        }
    }
    //通知:攔截到連接點之后要執(zhí)行的代碼
        @Around("logPointCut()")
    private Object printLog(ProceedingJoinPoint joinPoint) throws Throwable {
        //獲取連接點的方法簽名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //獲取方法簽名里的方法:方法簽名里有兩個方法:getReturnType   getMethod
        Method method = signature.getMethod();
        //獲取類
        Class<?> targetClass = method.getDeclaringClass();
        StringBuffer classAndMethod = new StringBuffer();

        // 獲取目標(biāo)方法上的Log注解
        Log methodAnnotation = method.getAnnotation(Log.class);

        // 判斷是否有LOG注解以及是否帶有ignore參數(shù)
        if (methodAnnotation != null) {
            classAndMethod.append(methodAnnotation.value());
        }
        //拼接目標(biāo)切入的類名稱和方法名稱
        String target = targetClass.getName() + "#" + method.getName();
        // 請求參數(shù)轉(zhuǎn)JSON罗晕,對日期進(jìn)行格式轉(zhuǎn)換并打印出所有為null的參數(shù)
        String params = JSONObject.toJSONStringWithDateFormat(joinPoint.getArgs(), dateFormat, SerializerFeature.WriteMapNullValue);
        //日志打印拼接的調(diào)用信息
        log.info(STRING_START + "{} 開始調(diào)用--> {} 參數(shù):{}", classAndMethod.toString(), target, params);

        long start = System.currentTimeMillis();
        //proceed()通過反射執(zhí)行目標(biāo)對象的連接點處的方法济欢;
        Object result = joinPoint.proceed();
        long timeConsuming = System.currentTimeMillis() - start;
        if (methodAnnotation != null && methodAnnotation.ignoreReturn()) {
            log.info("\n{} 調(diào)用結(jié)束<-- {} 耗時:{}ms" + STRING_END, classAndMethod.toString(), target, timeConsuming);
            return result;
        }
        // 響應(yīng)參數(shù)轉(zhuǎn)JSON,對日期進(jìn)行格式轉(zhuǎn)換并打印出所有為null的參數(shù)
        log.info("\n{} 調(diào)用結(jié)束<-- {} 返回值:{} 耗時:{}ms" + STRING_END, classAndMethod.toString(), target, JSONObject.toJSONStringWithDateFormat(result, dateFormat, SerializerFeature.WriteMapNullValue), timeConsuming);
      
        return result;
    }
}

實現(xiàn)類
@Service
@Slf4j
public class UserServiceImpl implements UserService{

    @Autowired
private UserMapper usermapper;
    @Override
    @Log
    public User getUser(Integer id) {
        User user=usermapper.getById(id);
        log.info("message: {}",user);
        return usermapper.getById(id);
    }
}

控制臺輸出
--------------------------->
 開始調(diào)用--> com.example.demo.service.serviceimpl.UserServiceImpl#getUser 參數(shù):[2]
2019-01-19 21:24:57.027 [http-nio-9091-exec-1] INFO  com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2019-01-19 21:24:57.406 [http-nio-9091-exec-1] INFO  com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2019-01-19 21:24:57.413 [http-nio-9091-exec-1] DEBUG c.e.demo.dao.UserMapper.getById : ==>  Preparing: SELECT * FROM user u WHERE u.id = ? 
2019-01-19 21:24:57.436 [http-nio-9091-exec-1] DEBUG c.e.demo.dao.UserMapper.getById : ==> Parameters: 2(Integer)
2019-01-19 21:24:57.468 [http-nio-9091-exec-1] DEBUG c.e.demo.dao.UserMapper.getById : <==      Total: 1
2019-01-19 21:24:57.470 [http-nio-9091-exec-1] INFO  c.e.d.s.serviceimpl.UserServiceImpl : message: User(id=2, name=321, birthday=2019-01-17, address=4)
2019-01-19 21:24:57.471 [http-nio-9091-exec-1] DEBUG c.e.demo.dao.UserMapper.getById : ==>  Preparing: SELECT * FROM user u WHERE u.id = ? 
2019-01-19 21:24:57.471 [http-nio-9091-exec-1] DEBUG c.e.demo.dao.UserMapper.getById : ==> Parameters: 2(Integer)
2019-01-19 21:24:57.484 [http-nio-9091-exec-1] DEBUG c.e.demo.dao.UserMapper.getById : <==      Total: 1
2019-01-19 21:24:57.516 [http-nio-9091-exec-1] INFO  c.example.demo.config.log.LogAspect : 
 調(diào)用結(jié)束<-- com.example.demo.service.serviceimpl.UserServiceImpl#getUser 返回值:{"address":"4","birthday":"2019-01-17","id":2,"name":"321"} 耗時:478ms
<----------------------------
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末小渊,一起剝皮案震驚了整個濱河市法褥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酬屉,老刑警劉巖挖胃,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異梆惯,居然都是意外死亡酱鸭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門垛吗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凹髓,“玉大人,你說我怎么就攤上這事怯屉∥狄ǎ” “怎么了饵沧?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赌躺。 經(jīng)常有香客問我狼牺,道長,這世上最難降的妖魔是什么礼患? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任是钥,我火速辦了婚禮,結(jié)果婚禮上缅叠,老公的妹妹穿的比我還像新娘悄泥。我一直安慰自己,他們只是感情好肤粱,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布弹囚。 她就那樣靜靜地躺著,像睡著了一般领曼。 火紅的嫁衣襯著肌膚如雪鸥鹉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天庶骄,我揣著相機(jī)與錄音毁渗,去河邊找鬼。 笑死瓢姻,一個胖子當(dāng)著我的面吹牛祝蝠,可吹牛的內(nèi)容都是我干的音诈。 我是一名探鬼主播幻碱,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼细溅!你這毒婦竟也來了褥傍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤喇聊,失蹤者是張志新(化名)和其女友劉穎恍风,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體誓篱,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡朋贬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了窜骄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锦募。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖邻遏,靈堂內(nèi)的尸體忽然破棺而出糠亩,到底是詐尸還是另有隱情虐骑,我是刑警寧澤赎线,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布廷没,位于F島的核電站,受9級特大地震影響垂寥,放射性物質(zhì)發(fā)生泄漏颠黎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一矫废、第九天 我趴在偏房一處隱蔽的房頂上張望盏缤。 院中可真熱鬧,春花似錦蓖扑、人聲如沸唉铜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潭流。三九已至,卻和暖如春柜去,著一層夾襖步出監(jiān)牢的瞬間灰嫉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工嗓奢, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留讼撒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓股耽,卻偏偏與公主長得像根盒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子物蝙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

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