SpringBoot使用AOP,內(nèi)部方法失效的解決方案
SpringBoot使用AOP,內(nèi)部方法失效
最近在使用AOP的時候,發(fā)現(xiàn)一個問題,普通的方法AOP就能夠有用,而內(nèi)部調(diào)用的方法AOP就會失效,下面重現(xiàn)下問題
AOP切面
@Aspect
@Component
public class AuthorityAspect {
@Pointcut("execution(* authority.service.AuthorityService.getExecutableSql(..))")
private void pointCut() {}
@Around(value = "pointCut()")
public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
String sql = (String) args[1];
args[1] = sql + " AOP ";
return joinPoint.proceed(args);
}
該切面的作用就是,當(dāng)執(zhí)行g(shù)etExecutableSql()方法,織入切面,獲取到該方法的參數(shù),修改參數(shù)然后再執(zhí)行該方法
現(xiàn)在有兩個方法
@Service
public class AuthorityService {
public String getExecutableSql(String dataSourceId, String sql, Object page){
return sql;
}
public String getInner(String dataSourceId, String sql, Object page){
String str = this.getExecutableSql(dataSourceId, sql, page);
return str;
}
}
- 一個是普通方法getExecutableSql(),
- 一個是在內(nèi)部調(diào)用了getExecutableSql()的getInner()方法
同時運行這兩個方法

可以發(fā)現(xiàn)內(nèi)部調(diào)用了getExecutableSql()的方法,AOP對它并沒有生效,直接調(diào)用的就生效了。在說原因前,我們先說說動態(tài)代理 因為AOP的原理就是動態(tài)代理
動態(tài)代理簡單來說就是在程序運行的過程中,自動生成一個指定的代理類,然后執(zhí)行程序,這個代理類可以在破壞原來被代理對象的情況下做一下額外的工作。
寫一個簡單的動態(tài)代理的例子
//接口
public interface ProxyService {
void save();
void email();
void register();
}
//實現(xiàn)類
@Service
public class ProxyServiceImpl implements ProxyService{
@Override
public void save() {
}
@Override
public void email() {
}
@Override
public void register() {
this.save();
this.email();
}
}
//獲得代理
public class ServiceProxy {
public static Object getProxy(Class<?> clazz,Object target){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(target, args);
System.out.println("after method: "+method.getName());
return invoke;
}
});
}
}
//測試類
public class ProxyTest {
public static void main(String[] args) {
ProxyService proxyService = (ProxyService) ServiceProxy.getProxy(ProxyService.class, new ProxyServiceImpl());
proxyService.register();
}
}
結(jié)果:

可以看到動態(tài)代理中,內(nèi)部方法調(diào)用也是沒有生效,通過對代理類的Class文件分析,我們可以知道只有通過代理類的實例執(zhí)行的方法才會進入到攔截處理中

而動態(tài)代理的方法真實調(diào)用,會使用真實被代理對象實例進行方法調(diào)用,故在實例方法中通過this獲取的都是被代理的真實對象的實例,而不是代理對象自身。通過Debug可以看到

this獲取的不是代理對象,因此無法進入攔截處理,所以代理增強的方法沒有執(zhí)行。原因知道了,那就解決辦法就是讓代理對象去調(diào)用這些方法,就能夠進入攔截處理了,修改下代碼
@Service
public class ProxyServiceImpl implements ProxyService{
@Override
public void save() {
}
@Override
public void email() {
}
@Override
public void register() {
//獲取代理對象
ProxyService proxyService = (ProxyService) ServiceProxy.getProxy(ProxyService.class, new ProxyServiceImpl());
proxyService.save();
proxyService.email();
}
}
執(zhí)行一下

在SpringBoot中可以用下面的方法,來使內(nèi)部調(diào)用的方法AOP也能對其生效
@Service
public class AuthorityService {
//獲取代理對象
@Autowired
private AuthorityService authorityService;
public String getExecutableSql(String dataSourceId, String sql, Object page){
return sql;
}
public String getInner(String dataSourceId, String sql, Object page){
String str = authorityService.getExecutableSql(dataSourceId, sql, page);
return str;
}
}

可以看到內(nèi)部調(diào)用的方法也生效了
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- springboot使用自定義注解實現(xiàn)aop切面日志
- SpringBoot使用AOP記錄接口操作日志詳解
- SpringBoot使用AOP實現(xiàn)統(tǒng)計全局接口訪問次數(shù)詳解
- 在springboot中使用AOP進行全局日志記錄
- Springboot使用@Valid 和AOP做參數(shù)校驗及日志輸出問題
- 詳解基于SpringBoot使用AOP技術(shù)實現(xiàn)操作日志管理
- SpringBoot使用AOP+注解實現(xiàn)簡單的權(quán)限驗證的方法
- SpringBoot中使用AOP打印接口日志的方法
- SpringBoot項目中使用AOP的方法
- Springboot 中使用 Aop代碼實戰(zhàn)教程
相關(guān)文章
SpringCloud Stream消息驅(qū)動實例詳解
這篇文章主要介紹了SpringCloud Stream消息驅(qū)動的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03
MyBatis執(zhí)行批處理操作的實現(xiàn)示例
在MyBatis中,批處理操作是一種高效執(zhí)行多條語句的方式,下面就來介紹一下MyBatis執(zhí)行批處理操作的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下2024-07-07
使用maven的profile構(gòu)建不同環(huán)境配置的方法
這篇文章主要介紹了使用maven的profile構(gòu)建不同環(huán)境配置的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01

