Spring AOP使用時の問題点


AOPを使用している間にいくつかの問題が発生しましたので、ここに記録しておきます
まずよく使うAOPスライスを書きます
スライス類AopLog
package com.mantis.aop.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mantis.aop.common.util.DataUtil;
import eu.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description:             Around  Before  Method.invoke   Around  After   AfterReturning
 *         Around  Before  Method.invoke   After   AfterThrowing
 * @author: wei.wang
 * @since: 2020/4/4 13:47
 * @history: 1.2020/4/4 created by wei.wang
 */
@Aspect
@Component
public class AopLog {

    private static Logger logger = LoggerFactory.getLogger(AopLog.class);

    /**
     *     ,   com.smec.fin.controller             service        
     */
    @Pointcut("execution(public * com.mantis.aop.controller..*.*(..))")
    public void log() {
        //     
    }

    /**
     *     ,   com.smec.fin.controller             service        
     */
    @Pointcut("execution(public * com.mantis.aop.service.impl..*.*(..))")
    public void log2() {
        //     
    }

    /**
     *     
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("log2()")
    public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
        logger.info("        ");
        Object result = point.proceed();
        logger.info("        ,   :{}", result);
        return result;
    }
}

サービスクラスAopServiceImpl
package com.mantis.aop.service.impl;

import com.mantis.aop.service.AopService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description:
 * @author: wei.wang
 * @since: 2020/10/24 12:45
 * @history: 1.2020/10/24 created by wei.wang
 */
@Service
public class AopServiceImpl implements AopService {


    @Override
    public void testAop(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        this.testAop2("testFinalMethod");
    }

    @Override
    public void testAop2(String str) {
        //this.testFinalMethod("testFinalMethod");
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl." + str);
    }

    public final void testFinalMethod(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
    }

    public void testFinalMethod2(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
    }
}

1.同方法の運転問題
AOPを使用しているときに同類の呼び出し時の接点が失効する問題があることを発見し、実行時にtestAopの接点のみが実行されていることを発見した.testAop 2の接点は実行されていない.これは、AOPエージェントを通過した後のオブジェクトが元のオブジェクトではなく、拡張方法を加えたエージェントオブジェクトであるため、エージェントオブジェクト呼び出しを使用すると拡張方法を実行することができる.ただし、ここではthis呼び出し、つまりAopServiceImplを使用します.エージェントオブジェクトではないため、拡張方法はありません.
2020-10-24 13:31:06.261  INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController  :       
2020-10-24 13:31:06.264  INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod

2020-10-24 13:31:06.274  INFO 13344 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         ,   :null

@AutowiredまたはResourceによる自己依存性の導入
注釈メソッドを使用して自己エージェント依存性を導入するには、構造の使用方法にループ依存の問題があることに注意してください.
    @Autowired
    AopServiceImpl aopService;

    @Override
    public void testAop(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        aopService.testAop2("testFinalMethod");
        System.out.println();
    }
2020-10-24 13:36:33.477  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController  :       
2020-10-24 13:36:33.480  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:36:33.488  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod
2020-10-24 13:36:33.488  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         ,   :null

2020-10-24 13:36:33.490  INFO 12528 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         ,   :null

露出エージェントクラスを開き、AopContext.currentProxy()方式でエージェントクラスを取得
エージェントクラスを暴露することにより,エージェントクラスを現在要求されているThreadLocalに追加し,使用時にThreadLocalからエージェントクラスを取得し,対応するメソッドを呼び出すのが実際の原理である.
メインメソッドに@EnableAspectJAutoProxy(exposeProxy=true)を加え、AOPコンテキストからエージェントを取得します.
    @Override
    public void testAop(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
        service.testAop2("testFinalMethod");
        System.out.println();
    }
2020-10-24 13:38:31.031  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.controller.AopController  :       
2020-10-24 13:38:31.035  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:38:31.047  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod
2020-10-24 13:38:31.048  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         ,   :null

2020-10-24 13:38:31.050  INFO 18828 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         ,   :null

2.finalキーワードの問題
Spring AOPのデフォルトではcglibが使用され、ターゲットオブジェクトのサブクラスエージェントオブジェクトが生成されます.ターゲットオブジェクトを呼び出す方法は、実際にはプロキシオブジェクトを呼び出す方法です.子クラスは親クラスのメソッドを継承できるため、一般的にターゲットクラスのメソッドはエージェントオブジェクトにあります.しかし、ターゲットクラスのメソッドにfinalキーがある場合、このメソッドは書き換えられないため、エージェントオブジェクトにはこのメソッドがないため、ターゲットオブジェクトのメソッドが呼び出されます.
finalキーワード付き
testFinalMethodメソッドにfinalキーワードが存在するため書き換えることができず、結果としてエージェントオブジェクトがこのメソッドを生成できないため、ターゲットオブジェクトメソッドを呼び出し、拡張されない
    @Override
    public void testAop(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
        service.testFinalMethod("testFinalMethod");
        System.out.println();
    }
    
    public final void testFinalMethod(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
    }
2020-10-24 13:47:46.907  INFO 15204 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethodtestFinalMethod

2020-10-24 13:47:46.916  INFO 15204 --- [nio-9000-exec-1] com.mantis.aop.aspect.AopLog             :         ,   :null

finalキーワードなし
testFinalMethodメソッドにはfinalキーワードが存在しないため、通常は強化が実行されます.
    @Override
    public void testAop(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str);
        AopServiceImpl service = AopContext.currentProxy() != null ? (AopServiceImpl) AopContext.currentProxy() : this;
        service.testFinalMethod2("testFinalMethod");
        System.out.println();
    }
    
    public final void testFinalMethod2(String str) {
        System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str);
    }
2020-10-24 13:50:51.018  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.controller.AopController  :       
2020-10-24 13:50:51.021  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog             :         
com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2
2020-10-24 13:50:51.029  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog             :         
com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethodtestFinalMethod
2020-10-24 13:50:51.030  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog             :         ,   :null

2020-10-24 13:50:51.031  INFO 13532 --- [nio-9000-exec-2] com.mantis.aop.aspect.AopLog             :         ,   :null