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
那么我們就能對springboot有更深入的認(rèn)識(shí),其實(shí)他相對于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)對象實(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è)參考,也希望大家多多支持腳本之家。
相關(guān)文章
MyBatis開發(fā)Dao層的兩種方式實(shí)現(xiàn)(原始Dao層開發(fā))
這篇文章主要介紹了MyBatis開發(fā)Dao層的兩種方式實(shí)現(xiàn)(原始Dao層開發(fā)),并對數(shù)據(jù)庫進(jìn)行增刪查改,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12Java實(shí)現(xiàn)抽獎(jiǎng)算法的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)抽獎(jiǎng)算法,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下2022-04-04Java使用自定義注解+反射實(shí)現(xiàn)字典轉(zhuǎn)換代碼實(shí)例
這篇文章主要介紹了Java使用自定義注解+反射實(shí)現(xiàn)字典轉(zhuǎn)換代碼實(shí)例,注解是一種能被添加到j(luò)ava代碼中的元數(shù)據(jù),類、方法、變量、參數(shù)和包都可以用注解來修飾,注解對于它所修飾的代碼并沒有直接的影響,需要的朋友可以參考下2023-09-09java實(shí)現(xiàn)學(xué)籍管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)學(xué)籍管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12