Springboot面接面プログラミング-カスタム注釈の実装


なぜカスタム注釈が存在するのでしょうか.1つのインタフェースはアクションを実行する必要がある場合がありますが、一部のインタフェースは必要ありません.カスタム注釈の適用は柔軟です.たとえば、注釈を登録するかどうかを検証するなど、インタフェースにカスタム注釈を加えるだけでブロックできます.また、ログインなどの重要な吊り下げインタフェース呼び出し操作もあります.ログをデータベースに記録する必要があります.カスタム注釈も必要です.次に、カスタム注釈の使用例を説明します.
1、コード
1、注釈の定義
package com.bootdo.clouddocommon.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
	String value() default "";
}


2、この注釈を実現する
package com.bootdo.clouddocommon.aspect;

import com.bootdo.clouddocommon.annotation.Log;
import com.bootdo.clouddocommon.context.FilterContextHandler;
import com.bootdo.clouddocommon.dto.LogDO;
import com.bootdo.clouddocommon.service.LogRpcService;
import com.bootdo.clouddocommon.utils.HttpContextUtils;
import com.bootdo.clouddocommon.utils.IPUtils;
import com.bootdo.clouddocommon.utils.JSONUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.BeforeAdvice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
public class LogAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    @Autowired
    LogRpcService logService;


    @Pointcut("@annotation(com.bootdo.clouddocommon.annotation.Log)")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //     
        Object result = point.proceed();
        //     (  )
        long time = System.currentTimeMillis() - beginTime;
        //      
        saveLog(point, time);
        return result;
    }

    void saveLog(ProceedingJoinPoint joinPoint, long time) throws InterruptedException {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogDO sysLog = new LogDO();
        Log syslog = method.getAnnotation(Log.class);
        if (syslog != null) {
            //       
            sysLog.setOperation(syslog.value());
        }
        //       
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");
        //      
        Object[] args = joinPoint.getArgs();
        try {
            String params = JSONUtils.beanToJson(args[0]).substring(0, 4999);
            sysLog.setParams(params);
        } catch (Exception e) {

        }
        //   request
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        //   IP  
        sysLog.setIp(IPUtils.getIpAddr(request));
        //    

        sysLog.setUserId(Long.parseLong(FilterContextHandler.getUserID() == null ? "000000" : FilterContextHandler.getUserID()));
        sysLog.setUsername(FilterContextHandler.getUsername() == null ? "" : FilterContextHandler.getUsername());
        sysLog.setTime((int) time);
        //       
        Date date = new Date();
        sysLog.setGmtCreate(date);
        //       
        logService.save(sysLog);//          ,     
    }
}

3、注釈の使用
 @Log("         ")
    @GetMapping("currentUserMenus")
    R currentUserMenus() {
        return R.ok().put("currentUserMenus",menuService.RouterDTOsByUserId(SecuityUtils.getCurrentUser().getId()));
    }

上の3歩で完成する
2、説明
まず前の文章のtarget注釈を説明します
1、Target注記
java.lang.annotation.Targetは、注釈の使用範囲javaを設定ためのものである.lang.annotation.ElementType Targetは、ElementTypeによって注釈の使用可能範囲を指定する列挙集合を以下の表に示す.
値をとる
注記の使用範囲
METHOD
メソッドに使用可能
TYPE
クラスまたはインタフェースで使用可能
ANNOTATION_TYPE
注記タイプ(@interfaceで修飾されたタイプ)に使用できます.
CONSTRUCTOR
構築方法に使用可能
FIELD
ドメインで使用可能
LOCAL_VARIABLE
ローカル変数で使用可能
PACKAGE
Javaファイルを記録するためのpackage情報
PARAMETER
パラメータに使用可能
2 Retention注記
これは簡単で、この注釈を表す宣言周期で、周期が過ぎると役に立たない.
カテゴリ
宣言期間
RetentionPolicy.SOURCE
注釈はソースファイルにのみ保持され、Javaファイルがclassファイルにコンパイルされると、注釈は破棄されます.
RetentionPolicy.CLASS
注記はclassファイルに保存されますが、jvmがclassファイルをロードするときに破棄されます.これはデフォルトのライフサイクルです.
RetentionPolicy.RUNTIME
注記はclassファイルに保存されるだけでなく、jvmがclassファイルをロードした後も存在します.
3 Pointcut
@Pointcut("@annotation(com.bootdo.clouddocommon.annotation.Log)")
    public void logPointCut() {
    }

ここに何の役に立つのか分からない人もいるかもしれませんが、主に次の方法に使われています.
@Around("logPointCut()")      
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //     
        Object result = point.proceed();
        //     (  )
        long time = System.currentTimeMillis() - beginTime;
        //      
        saveLog(point, time);
        return result;
    }

もちろんここではlogPointCut()という方法を使わずにそのまま書くことができます
@Around("@annotation(com.bootdo.clouddocommon.annotation.Log)") 
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //     
        Object result = point.proceed();
        //     (  )
        long time = System.currentTimeMillis() - beginTime;
        //      
        saveLog(point, time);
        return result;
    }

4、point.proceed()メソッド
上記のコードでは,各インタフェースの実行に要する時間を計算したが,プログラムはどのように実行済みを判断するのか,これがループ通知の強みである.ここにObject result=pointを付けなければならないからです.proceed();currentUserMenusというメソッドを実行することで、メソッドの実行が完了した後に消費時間を計算できます.
オービット通知:ターゲットメソッドが実行されるか、いつ実行されるか、実行時にメソッドパラメータを置き換える必要があるか、実行が完了したら戻り値を置き換える必要があるかを決定できます.
5、ProceedingJoinPointとJoinPoint
ProceedingJoinPointはJoinPointサブインタフェースを継承し、接続ポイントメソッドを実行するための2つの方法を追加しました.
方法
説明する
java.lang.Object proceed() throws java.lang.Throwable
ターゲットオブジェクトの接続点を反射して実行する方法
java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable
ターゲットオブジェクトの接続点での方法を反射で実行しますが、元のパラメータを新しいパラメータで置き換えます.
@Aroundはメソッドの実行前後で実行が強化されています.彼の最も強力な点は、元のパラメータを置き換えることができ、メソッドの実行結果を変更することです.
注意:@Aroundを使用することなく、beforeやafterその他に影響を与えることはないが、@Aroundを使用すると、Object result=pointが必要となる.proceed();,この方法を実行し、return resultが必要であることを示す.結果を返します.これがなければ、元のメソッドは値を返しません.
この文章はdemoに基づいて書かれているので、興味のある人はダウンロードして実行してみてください.ダウンロード先:https://download.csdn.net/download/qq_28483283/11233595フロントエンドはvueで、バックエンドはspringboot+springcloud ps:ダウンロードポイントを設定したくないのですが、csdnは強制的に5ポイントを要求して、私も仕方がありません.