1. 程式人生 > 程式設計 >關於Spring AOP使用時的一些問題彙總

關於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的切點,testAop2的切點沒有執行,這是因為經過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

總結

到此這篇關於Spring AOP使用時的一些問題彙總的文章就介紹到這了,更多相關Spring AOP使用時的問題內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!