面試官:Spring Aop 常見(jiàn)注解和執(zhí)行順序
閱讀本文大概需要 3.5 分鐘。
來(lái)自:juejin.cn/post/7062506923194581029
@Before前置通知:目標(biāo)方法之前執(zhí)行@After后置通知:目標(biāo)方法之后執(zhí)行(始終執(zhí)行)@AfterReturning返回之后通知:執(zhí)行方法結(jié)束之前執(zhí)行(異常不執(zhí)行)@AfterThrowing異常通知:出香異常后執(zhí)行@Around環(huán)繞通知:環(huán)繞目標(biāo)方法執(zhí)行
常見(jiàn)問(wèn)題
示例代碼
配置文件
start.spring.io 上面去快速創(chuàng)建spring-boot 應(yīng)用。因?yàn)楸救私?jīng)常手動(dòng)去網(wǎng)上貼一些依賴導(dǎo)致,依賴沖突服務(wù)啟動(dòng)失敗等一些問(wèn)題。
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 {
# 其實(shí)這里也可以不增加 web 配置,為了試驗(yàn)簡(jiǎn)單,大家請(qǐng)忽略
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()
}
接口類
如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,則默認(rèn)采用JDK動(dòng)態(tài)代理 如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口,則采用進(jìn)行動(dòng)態(tài)代理 如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,且強(qiáng)制Cglib,則使用cglib代理
DefaultAopProxyFactory 大家有興趣可以去看看。public interface CalcService {
public int div(int x, int y);
}
實(shí)現(xiàn)類
@Service
public class CalcServiceImpl implements CalcService {
@Override
public int div(int x, int y) {
int result = x / y;
System.out.println("====> CalcServiceImpl 被調(diào)用了,我們的計(jì)算結(jié)果是:" + result);
return result;
}
}
aop 攔截器

@EnableAspectJAutoProxy 注解。定義 Aspect 定義切面 定義 Pointcut 就是定義我們切入點(diǎn) 定義具體的通知,比如: @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 環(huán)繞通知之前 AAA");
retVal = proceedingJoinPoint.proceed();
System.out.println("----===>> @Around 環(huán)繞通知之后 BBB");
return retVal;
}
}
測(cè)試類

執(zhí)行結(jié)論

多切面的情況

代理失效場(chǎng)景
AServer#a 的方法攔截器(MethodInterceptor)鏈, 當(dāng)我們?cè)?a 方法內(nèi)直接執(zhí)行b(), 其實(shí)本質(zhì)就相當(dāng)于 this.b() , 這個(gè)時(shí)候由執(zhí)行 a方法是調(diào)用到 a 的原始對(duì)象相當(dāng)于是 this 調(diào)用,那么會(huì)導(dǎo)致 b() 方法的代理失效。這個(gè)問(wèn)題也是我們開發(fā)者在開發(fā)過(guò)程中最常遇到的一個(gè)問(wèn)題。@Service
public class AService {
public void a() {
System.out.println("...... a");
b();
}
public void b() {
System.out.println("...... b");
}
}
推薦閱讀:
某游戲研發(fā)公司給每個(gè)工位都裝攝像頭,網(wǎng)友:堪比坐牢!
騰訊二面:@Bean 與 @Component 用在同一個(gè)類上,會(huì)怎么樣?
互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G) 內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬(wàn)并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper......等技術(shù)棧!
?戳閱讀原文領(lǐng)?。?/span> 朕已閱
評(píng)論
圖片
表情


