SpringBoot中創(chuàng)建的AOP不生效的原因及解決
SpringBoot 創(chuàng)建AOP不生效的原因
最近在學(xué)習(xí)SpringBoot,今天學(xué)習(xí)了Aop的注冊方式,原理很簡單,配置也很簡單,但是我注冊了切面之后切面一直不生效,是為什么呢?查了好久的資料終于發(fā)現(xiàn)了原因,可以看下圖我的切面注冊類并沒有問題

然后在網(wǎng)上偶然看到可能是主程序掃描的原因,才發(fā)現(xiàn)了原因,可以看到我的顯示方式本來是flat的,那樣的話就很難找出原因了

修改為hirerchical就可以很清楚的看出問題

可以看出,我的主程序和切面類并不在一個(gè)包中,那么主程序掃描不到切面類,自然就不會(huì)注冊切面了,最簡單的解決方式就是在主程序中添加一個(gè)注解@ComponentScan

那么我們就能對(duì)springboot有更深入的認(rèn)識(shí),其實(shí)他相對(duì)于ssm所有的簡化步驟關(guān)鍵在于主程序,他起到了一個(gè)封裝加載的步驟,不主動(dòng)聲明的情況下他會(huì)掃描和自己在同一個(gè)包下面的所有類,并根據(jù)注解自動(dòng)注冊,那么以后寫項(xiàng)目時(shí)最好的方式就是將主程序放在主包下,然后所有的這些類都放在子包中即可
SpringBoot aop無效的情況
項(xiàng)目結(jié)構(gòu)

package com.example.demo.inter;
public interface CustomerService {
void doSomething1();
void doSomething2();
}
package com.example.demo.inter;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
@Service
public class CustomerServiceImpl implements CustomerService {
@Override
public void doSomething1() {
System.out.println("CustomerServiceImpl.doSomething1()");
doSomething2();
((CustomerService) AopContext.currentProxy()).doSomething2();
}
@Override
public void doSomething2() {
System.out.println("CustomerServiceImpl.doSomething2()");
}
}
package com.example.demo;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class CustomerServiceInterceptor {
@Before("execution(* com.example.demo.inter..*.*(..))")
public void doBefore() {
System.out.println("do some important things before...");
}
}
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@EnableAspectJAutoProxy(proxyTargetClass=true, exposeProxy=true)
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
package com.example.demo;
import com.example.demo.inter.CustomerService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Autowired
CustomerService customerService;
@Test
public void testAOP() {
customerService.doSomething1();
}
@Test
void contextLoads() {
}
}
運(yùn)行下testAOP,為啥doSomething2()沒有切面效果,使用AopContext.currentProxy就可以了?
攔截器的實(shí)現(xiàn)原理就是動(dòng)態(tài)代理,實(shí)現(xiàn)AOP機(jī)制。Spring 的代理實(shí)現(xiàn)有兩種:一是基于 JDK Dynamic Proxy 技術(shù)而實(shí)現(xiàn)的;二是基于 CGLIB 技術(shù)而實(shí)現(xiàn)的。如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,在默認(rèn)情況下Spring會(huì)采用JDK的動(dòng)態(tài)代理實(shí)現(xiàn)AOP,CustomerServerImpl正是這種情況。
JDK動(dòng)態(tài)代理生成的CustomerServiceImpl的代理類翻譯過來如下:
package com.example.demo;
import com.example.demo.inter.CustomerService;
public class CustomerServiceProxy implements CustomerService {
private CustomerService customerService;
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
public void doSomething1() {
doBefore();
customerService.doSomething1();
// 默認(rèn),所以不會(huì)執(zhí)行doBefore
customerService.doSomething2();
// 加入 AopContext.currentProxy的效果,完成切面效果
this.doSomething2();
}
public void doSomething2() {
doBefore();
customerService.doSomething2();
}
private void doBefore() {
System.out.println("do some important things before...");
}
}
這樣很直觀地明白為啥要使用AopContext.currentProxy了。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot中使用AOP打印接口日志的方法
- springboot?aop里的@Pointcut()的配置方式
- SpringBoot AOP方式實(shí)現(xiàn)多數(shù)據(jù)源切換的方法
- SpringBoot項(xiàng)目中使用AOP的方法
- 詳解基于SpringBoot使用AOP技術(shù)實(shí)現(xiàn)操作日志管理
- springboot配置aop切面日志打印過程解析
- SpringBoot使用AOP實(shí)現(xiàn)統(tǒng)計(jì)全局接口訪問次數(shù)詳解
- SpringBoot中使用AOP實(shí)現(xiàn)日志記錄功能
- SpringBoot使用AOP+注解實(shí)現(xiàn)簡單的權(quán)限驗(yàn)證的方法
- SpringBoot中AOP的多種用途與實(shí)踐指南
相關(guān)文章
詳解MyBatis中Executor執(zhí)行SQL語句的過程
MyBatis中獲取SqlSession時(shí)會(huì)創(chuàng)建執(zhí)行器Executor并存放在SqlSession中,本篇文章將以MapperMethod的execute() 方法作為起點(diǎn),對(duì)MyBatis中的一次實(shí)際執(zhí)行請求進(jìn)行說明,并結(jié)合源碼對(duì)執(zhí)行器Executor的原理進(jìn)行闡釋2023-07-07
SpringBoot簡單實(shí)現(xiàn)定時(shí)器過程
這篇文章主要介紹了SpringBoot簡單實(shí)現(xiàn)定時(shí)器過程,對(duì)于Java后端來說肯定實(shí)現(xiàn)定時(shí)功能肯定是使用到Spring封裝好的定時(shí)調(diào)度Scheduled2023-04-04
解決gateway配合nacos路由報(bào)錯(cuò):Unable to find instance&
這篇文章主要介紹了解決gateway配合nacos路由報(bào)錯(cuò):Unable to find instance for XXX問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-06-06
SpringBoot 整合 Shiro 密碼登錄的實(shí)現(xiàn)代碼
這篇文章主要介紹了SpringBoot 整合 Shiro 密碼登錄的實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
Maven統(tǒng)一版本管理的實(shí)現(xiàn)
在使用Maven多模塊結(jié)構(gòu)工程時(shí),配置版本是一個(gè)比較頭疼的事,本文主要介紹了Maven統(tǒng)一版本管理的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
一篇文章了解Jackson注解@JsonFormat及失效解決辦法
這篇文章主要給大家介紹了關(guān)于如何通過一篇文章了解Jackson注解@JsonFormat及失效解決辦法的相關(guān)資料,@JsonFormat注解是一個(gè)時(shí)間格式化注解,用于格式化時(shí)間,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11

