面試官:Spring Aop 常見註解和執行順序

發布: 2023-08-15 16:32:49
轉載
682 人瀏覽過

最近,我在給很多人做履歷修改和模擬面試的時候,有部分朋友和我回饋Spring AOP的面試題,今天就和大家來問。

Spring 一開始最強大的就是 IOC / AOP 兩大核心功能,我們今天一起來學習 Spring AOP 常見註解和執行順序。

Spring 面試核心點:

IOC、AOP、Bean注入、Bean的生命週期、Bean的循環依賴

首先我們一起來回顧Spring Aop 中常用的幾個註解:

  • #@Before前置通知:目標方法之前執行
  • @After後置通知:目標方法之後執行(總是執行)
  • #@AfterReturning傳回之後通知:執行方法結束先前執行(異常不執行)
  • @AfterThrowing異常通知:出香異常後執行
  • @Around環繞通知:環繞目標方法執行

常見問題

1、你一定知道Spring , 那說說Aop 的去全部通知順序, Spring Boot 或Spring Boot 2 對aop 的執行順序影響?

2、說說你在 AOP 中遇到的那些坑?

範例程式碼

#下面我們先快速建立一個spring aop 的demo 程式來一起討論spring aop 中的一些細節。

設定檔

為了方便我直接使用spring-boot 進行快速的項目搭建,大家可以使用idea 的spring-boot 專案快速建立功能,或是去start.spring.io上面去快速建立spring-boot 應用程式。

因為本人經常手動去網路上貼上一些依賴導致,依賴衝突服務啟動失敗等一些問題。

plugins { id 'org.springframework.boot' version '2.6.3' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group 'io.zhengsh' version '1.0-SNAPSHOT' repositories { mavenCentral() maven { url 'https://repo.spring.io/milestone' } maven { url 'https://repo.spring.io/snapshot' } } dependencies { # 其实这里也可以不增加 web 配置,为了试验简单,大家请忽略 implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-aop' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() }
登入後複製

介面類別

#首先我們需要定義一個介面。我們這裡可以再來回顧一下JDK 的預設代理實現的選擇:

  • 如果目標物件實現了接口,則預設採用JDK動態代理
  • 如果目標物件沒有實現接口,則採用進行動態代理
  • 如果目標物件實現了接口,且強制Cglib,則使用cglib代理

這塊的邏輯在DefaultAopProxyFactory大家有興趣可以去看看。

public interface CalcService { public int div(int x, int y); }
登入後複製

實作類別

這裡我門就簡單一點做一個除法操作,可以模擬正常也可以很容易的模擬錯誤。

@Service public class CalcServiceImpl implements CalcService { @Override public int div(int x, int y) { int result = x / y; System.out.println("====> CalcServiceImpl 被调用了,我们的计算结果是:" + result); return result; } }
登入後複製

aop 攔截器

#申明一個攔截器我們要為當前物件增加@Aspect 和@Component ,筆者之前也是才踩過這樣的坑,只加了一個。

其实这块我刚开始也不是很理解,但是我看了 Aspect 注解的定义我就清楚了

面試官:Spring Aop 常見註解和執行順序

这里面根本就没有 Bean 的定义。所以我们还是乖乖的加上两个注解。

还有就是如果当测试的时候需要开启Aop 的支持为配置类上增加@EnableAspectJAutoProxy注解。

其实 Aop 使用就三个步骤:

  • 定义 Aspect 定义切面
  • 定义 Pointcut 就是定义我们切入点
  • 定义具体的通知,比如: @After, @Before 等。
@Aspect @Component public class MyAspect { @Pointcut("execution(* io.zhengsh.spring.service.impl..*.*(..))") public void divPointCut() { } @Before("divPointCut()") public void beforeNotify() { System.out.println("----===>> @Before 我是前置通知"); } @After("divPointCut") public void afterNotify() { System.out.println("----===>> @After 我是后置通知"); } @AfterReturning("divPointCut") public void afterReturningNotify() { System.out.println("----===>> @AfterReturning 我是前置通知"); } @AfterThrowing("divPointCut") public void afterThrowingNotify() { System.out.println("----===>> @AfterThrowing 我是异常通知"); } @Around("divPointCut") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object retVal; System.out.println("----===>> @Around 环绕通知之前 AAA"); retVal = proceedingJoinPoint.proceed(); System.out.println("----===>> @Around 环绕通知之后 BBB"); return retVal; } }
登入後複製

测试类

其实我这个测试类,虽然用了 @Test 注解,但是我这个类更加像一个 main 方法把:如下所示:

面試官:Spring Aop 常見註解和執行順序

执行结论

结果记录:spring 4.x, spring-boot 1.5.9

无法现在依赖,所以无法试验

我直接说一下结论:Spring 4 中环绕通知是在最里面执行的

结果记录:spring 版本5.3.15 springboot 版本2.6.3

面試官:Spring Aop 常見註解和執行順序
img

多切面的情况

多个切面的情况下,可以通过@Order指定先后顺序,数字越小,优先级越高。如下图所示:

面試官:Spring Aop 常見註解和執行順序

代理失效场景

下面一种场景会导致 aop 代理失效,因为我们在执行 a 方法的时候其实本质是执行AServer#a的方法拦截器(MethodInterceptor)链, 当我们在 a 方法内直接执行b(), 其实本质就相当于 this.b() , 这个时候由执行 a方法是调用到 a 的原始对象相当于是 this 调用,那么会导致 b() 方法的代理失效。这个问题也是我们开发者在开发过程中最常遇到的一个问题。

@Service public class AService { public void a() { System.out.println("...... a"); b(); } public void b() { System.out.println("...... b"); } }
登入後複製

以上是面試官:Spring Aop 常見註解和執行順序的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:Java后端技术全栈
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!