1. ホーム
  2. Java

AOP -- アノテーション @Aspect, @Pointcut

2022-03-02 03:10:03

内容

1. 基本コンセプト

1.1. タンジェントクラス @Aspect

1.2. カットポイント @ポイントカット

1.3. アドバイス

1.4.ジョインポイント

1.5. 演算子の使用方法

1.6. アノテーション(annotationType)

1.7. プロキシオブジェクト 

1.8. カットアノテーションの呼び出し

 2. コードの表示


前に書く。開発プロセスでは、各メソッドの実行ログ、戻り値の解析、AOPに関する関連知識ポイントの簡単な整理が必要です。

1. 基本概念

1.1. タンジェントクラス @Aspect

Aspect、@Componentアノテーションを使用して、タンジェントクラスを定義します(下図)。

1.2. カットポイント @Pointcut

 (1) カット方法の指定

<スパン 実行式

最初の * は、次のようなメソッドの戻り値にマッチすることを意味します。

<スパン ... (ドット2つ)は0個以上を意味し

は、モジュールパッケージとそのサブパッケージを示します。

2つ目の*は全クラスを示します。

3番目の*は、以下のすべてのメソッドを示します。

<スパン 2番目は... メソッドの任意の数のパラメータを示す

    //org.jeecg.modules.dlglong.controller;
    //com.sd3e.projectmanager.controller.acceptanceApplication;

    @Pointcut("execute(public * org.jeecg.modules. *. *Controller.*(...)) ||execution(public * com.*.projectmanager... *. *Controller.*(...)) ")
    public void excudeService() {
        
    }

 @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
    	long time1 = System.currentTimeMillis();	
        Object result = pjp.proceed();
        long time2 = System.currentTimeMillis();
        log.debug("Get JSON data Time consumed: "+(time2-time1)+"ms");
        long start=System.currentTimeMillis();
        this.parseDictText(result);
        long end=System.currentTimeMillis();
        log.debug("Inject dictionary to JSON data Time consumed "+(end-start)+"ms");
        return result;
    }

    @Pointcut("execute(public * com.rest.module. *. *(...)) ")
    public void getMethods() {
    }

    @Pointcut("@annotation(org.jeecg.common.aspect.annotation.PermissionData)")
    public void pointCut() {

    }
package org.jeecg.common.aspect.annotation;

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

Target; /**
  * Data permission annotation
 * @Author taoyan
 * @Date April 11, 2019
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
public @interface PermissionData {
	/**
	 * Not used for now
	 * @return
	 */
	String value() default "";
	
	
	/**
	 * Configure the component path of the menu, used for data permissions
	 */
	String pageComponent() default "";
}
    @Pointcut("@annotation(com.rest.utils.SysPlatLog)")
    public void withAnnotationMethods() {

    }
public @interface SysPlatLog {
    // Operation name
    String operateName() default "";
    // operation description
    String logNote() default "";
}

 (2) アノテーションの指定

ここでは、カスタムアノテーションクラスを作成し、メソッドが動作するようにアノテーションしています。

@Before Execute before the cutpoint method

@After Executed after the cutpoint method

@AfterReturning Executed after the cutpoint method returns

@AfterThrowing Execute after a cutpoint method throws an exception

@Around is a wrap-around enhancement that controls the execution of the tangent before and after the execution of the tangent

//aop proxy object
Object aThis = joinPoint.getThis();
//proxied object
Object target = joinPoint.getTarget();

	@AutoLog(value = "ws_xbx-paginated-list-query")
	@ApiOperation(value="ws_xbx-paginated-list-query", notes="ws_xbx-paginated-list-query")
	@GetMapping(value = "/list")
	@PermissionData(pageComponent="sd3e/actDemo/WsXbxList")//sys_permission table component path component field
	public Result<? > queryPageList(WsXbx wsXbx,
								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
								   HttpServletRequest req) {
		QueryWrapper<WsXbx> queryWrapper = QueryGenerator.initQueryWrapper(wsXbx, req.getParameterMap());
		Page<WsXbx> page = new Page<WsXbx>(pageNo, pageSize);
		IPage<WsXbx> pageList = wsXbxService.page(page, queryWrapper);
		return Result.OK(pageList);
	}

@SysPlatLog(operatorName = "View Details",logNote = "View Details")
@SneakyThrows
public Result getItem(@RequestParam(required = false) String bs){
}

package com.npc.rest.utils;

import com.npc.rest.common.properties.AppSupPlatProperties;
import com.sys.model.SysLog;
import lombok.extern.slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect;
import java.util.*;

@Aspect
@Slf4j
@Component
public class SysPlatLogAspect {

    /**
     * Specify the cut
     */
    @Pointcut("execution(public * com.rest.module. *. *(...)) ")
    public void getMethods() {
   }
    /**
     * Specify the annotation
     */
    @Pointcut("@annotation(com.rest.utils.SysPlatLog)")
    public void withAnnotationMethods() {
    }

    /***
     * Intercept the control layer operation log
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @After(value = "getMethods() && withAnnotationMethods()")
    public void recordLog(JoinPoint joinPoint) throws Throwable {
        SysLog sysLog = new SysLog();
        SysPlatLog sysPlatLog = getInter(joinPoint);
        sysLog.setOperateName(sysPlatLog.operateName());
        sysLog.setLogNote(sysPlatLog.logNote());
        sysLog.setLogTime(new Date());
        sysLog.setAppCode(AppSupPlatProperties.getAppCode());
    }

    public SysPlatLog getInter(JoinPoint joinPoint) throws ClassNotFoundException {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    SysPlatLog sysPlatLog = method.getAnnotation(SysPlatLog.class);
                    return sysPlatLog;
                }
            }
        }
        return null;
    }
}

1.3.アドバイス

エントリーポイントで行われるエンハンスメント処理で、主に5つの注釈がある。 

@Before Execute before the cutpoint method

@After Executed after the cutpoint method

@AfterReturning Executed after the cutpoint method returns

@AfterThrowing Execute after a cutpoint method throws an exception

@Around is a wrap-around enhancement that controls the execution of the tangent before and after the execution of the tangent

1.4. ジョインポイント

メソッドで、パラメータ JoinPoint を結合点オブジェクトとして使用し、現在のカットインメソッドのパラメータやプロキシクラスなどを取得することで、何らかの情報を記録したり、何らかの情報を検証したりすることができるようになります。

1.5. 演算子の使用法

&&、 ||、 !を使用します。の有無の関係を表す接線表現を組み合わせるには、3つの演算子を使用します。 

   1.2. 例題はコードに記載

1.6. アノテーション(annotationType)

指定されたアノテーションがエントリポイントであるメソッドにマッチします。

1.7. プロキシオブジェクト 

//aop proxy object
Object aThis = joinPoint.getThis();
//proxied object
Object target = joinPoint.getTarget();

1.8. タンジェントアノテーションの呼び出し

	@AutoLog(value = "ws_xbx-paginated-list-query")
	@ApiOperation(value="ws_xbx-paginated-list-query", notes="ws_xbx-paginated-list-query")
	@GetMapping(value = "/list")
	@PermissionData(pageComponent="sd3e/actDemo/WsXbxList")//sys_permission table component path component field
	public Result<? > queryPageList(WsXbx wsXbx,
								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
								   HttpServletRequest req) {
		QueryWrapper<WsXbx> queryWrapper = QueryGenerator.initQueryWrapper(wsXbx, req.getParameterMap());
		Page<WsXbx> page = new Page<WsXbx>(pageNo, pageSize);
		IPage<WsXbx> pageList = wsXbxService.page(page, queryWrapper);
		return Result.OK(pageList);
	}


@SysPlatLog(operatorName = "View Details",logNote = "View Details")
@SneakyThrows
public Result getItem(@RequestParam(required = false) String bs){
}

 2. コードの表示

package com.npc.rest.utils;

import com.npc.rest.common.properties.AppSupPlatProperties;
import com.sys.model.SysLog;
import lombok.extern.slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect;
import java.util.*;

@Aspect
@Slf4j
@Component
public class SysPlatLogAspect {

    /**
     * Specify the cut
     */
    @Pointcut("execution(public * com.rest.module. *. *(...)) ")
    public void getMethods() {
   }
    /**
     * Specify the annotation
     */
    @Pointcut("@annotation(com.rest.utils.SysPlatLog)")
    public void withAnnotationMethods() {
    }

    /***
     * Intercept the control layer operation log
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @After(value = "getMethods() && withAnnotationMethods()")
    public void recordLog(JoinPoint joinPoint) throws Throwable {
        SysLog sysLog = new SysLog();
        SysPlatLog sysPlatLog = getInter(joinPoint);
        sysLog.setOperateName(sysPlatLog.operateName());
        sysLog.setLogNote(sysPlatLog.logNote());
        sysLog.setLogTime(new Date());
        sysLog.setAppCode(AppSupPlatProperties.getAppCode());
    }

    public SysPlatLog getInter(JoinPoint joinPoint) throws ClassNotFoundException {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    SysPlatLog sysPlatLog = method.getAnnotation(SysPlatLog.class);
                    return sysPlatLog;
                }
            }
        }
        return null;
    }
}