Spring AOP使用時の問題点
AOPを使用している間にいくつかの問題が発生しましたので、ここに記録しておきます
まずよく使うAOPスライスを書きます
スライス類AopLog
サービスクラスAopServiceImpl
1.同方法の運転問題
AOPを使用しているときに同類の呼び出し時の接点が失効する問題があることを発見し、実行時にtestAopの接点のみが実行されていることを発見した.testAop 2の接点は実行されていない.これは、AOPエージェントを通過した後のオブジェクトが元のオブジェクトではなく、拡張方法を加えたエージェントオブジェクトであるため、エージェントオブジェクト呼び出しを使用すると拡張方法を実行することができる.ただし、ここではthis呼び出し、つまりAopServiceImplを使用します.エージェントオブジェクトではないため、拡張方法はありません.
@AutowiredまたはResourceによる自己依存性の導入
注釈メソッドを使用して自己エージェント依存性を導入するには、構造の使用方法にループ依存の問題があることに注意してください.
露出エージェントクラスを開き、AopContext.currentProxy()方式でエージェントクラスを取得
エージェントクラスを暴露することにより,エージェントクラスを現在要求されているThreadLocalに追加し,使用時にThreadLocalからエージェントクラスを取得し,対応するメソッドを呼び出すのが実際の原理である.
メインメソッドに@EnableAspectJAutoProxy(exposeProxy=true)を加え、AOPコンテキストからエージェントを取得します.
2.finalキーワードの問題
Spring AOPのデフォルトではcglibが使用され、ターゲットオブジェクトのサブクラスエージェントオブジェクトが生成されます.ターゲットオブジェクトを呼び出す方法は、実際にはプロキシオブジェクトを呼び出す方法です.子クラスは親クラスのメソッドを継承できるため、一般的にターゲットクラスのメソッドはエージェントオブジェクトにあります.しかし、ターゲットクラスのメソッドにfinalキーがある場合、このメソッドは書き換えられないため、エージェントオブジェクトにはこのメソッドがないため、ターゲットオブジェクトのメソッドが呼び出されます.
finalキーワード付き
testFinalMethodメソッドにfinalキーワードが存在するため書き換えることができず、結果としてエージェントオブジェクトがこのメソッドを生成できないため、ターゲットオブジェクトメソッドを呼び出し、拡張されない
finalキーワードなし
testFinalMethodメソッドにはfinalキーワードが存在しないため、通常は強化が実行されます.
まずよく使う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