关于Spring AOP使用时的一些问题汇总
在使用AOP的时候遇到了一些问题,特此记录一下
首先写一个常用的AOP切片
切片类AopLog
packagecom.mantis.aop.aspect; importcom.fasterxml.jackson.databind.ObjectMapper; importcom.mantis.aop.common.util.DataUtil; importeu.bitwalker.useragentutils.UserAgent; importorg.aspectj.lang.JoinPoint; importorg.aspectj.lang.ProceedingJoinPoint; importorg.aspectj.lang.annotation.*; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.springframework.stereotype.Component; importorg.springframework.validation.BeanPropertyBindingResult; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.util.ArrayList; importjava.util.Arrays; importjava.util.Enumeration; importjava.util.List; importjava.util.stream.Collectors; /** *@Description:执行顺序正常顺序AroundBeforeMethod.invokeAroundAfterAfterReturning *异常顺序AroundBeforeMethod.invokeAfterAfterThrowing *@author:wei.wang *@since:2020/4/413:47 *@history:1.2020/4/4createdbywei.wang */ @Aspect @Component publicclassAopLog{ privatestaticLoggerlogger=LoggerFactory.getLogger(AopLog.class); /** *定义切点,切点为com.smec.fin.controller包和子包里任意方法的执行和service层所有方法的执行 */ @Pointcut("execution(public*com.mantis.aop.controller..*.*(..))") publicvoidlog(){ //定义切点 } /** *定义切点,切点为com.smec.fin.controller包和子包里任意方法的执行和service层所有方法的执行 */ @Pointcut("execution(public*com.mantis.aop.service.impl..*.*(..))") publicvoidlog2(){ //定义切点 } /** *环绕通知 * *@parampoint *@return *@throwsThrowable */ @Around("log2()") publicObjectaroundLog(ProceedingJoinPointpoint)throwsThrowable{ logger.info("开始执行环绕操作"); Objectresult=point.proceed(); logger.info("执行环绕操作结束,返回值:{}",result); returnresult; } }
服务类AopServiceImpl
packagecom.mantis.aop.service.impl; importcom.mantis.aop.service.AopService; importorg.springframework.aop.framework.AopContext; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.stereotype.Service; /** *@Description: *@author:wei.wang *@since:2020/10/2412:45 *@history:1.2020/10/24createdbywei.wang */ @Service publicclassAopServiceImplimplementsAopService{ @Override publicvoidtestAop(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop"+str); this.testAop2("testFinalMethod"); } @Override publicvoidtestAop2(Stringstr){ //this.testFinalMethod("testFinalMethod"); System.out.println("com.mantis.aop.service.AopService.AopServiceImpl."+str); } publicfinalvoidtestFinalMethod(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod"+str); } publicvoidtestFinalMethod2(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod"+str); } }
1.同方法运行问题
在使用AOP时我们发现存在同类中调用时切点失效问题,在执行时我们发现只执行了testAop的切点,testAop2的切点没有执行,这是因为经过AOP代理后的对象都已经不是原来的对象了,而是加入了增强方法的代理对象,使用代理对象调用时可以执行增强方法,但是这里是使用this调用的,也就是AopServiceImpl,因为不是代理对象就没有增强方法。
2020-10-2413:31:06.261INFO13344---[nio-9000-exec-1]com.mantis.aop.controller.AopController:方法开始执行 2020-10-2413:31:06.264INFO13344---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:开始执行环绕操作 com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2 com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod 2020-10-2413:31:06.274INFO13344---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:执行环绕操作结束,返回值:null
用@Autowired或Resource引入自身依赖
使用注解方法引入自身代理依赖,注意使用构造的方式会有循环依赖问题
@Autowired AopServiceImplaopService; @Override publicvoidtestAop(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop"+str); aopService.testAop2("testFinalMethod"); System.out.println(); }
2020-10-2413:36:33.477INFO12528---[nio-9000-exec-1]com.mantis.aop.controller.AopController:方法开始执行 2020-10-2413:36:33.480INFO12528---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:开始执行环绕操作 com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2 2020-10-2413:36:33.488INFO12528---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:开始执行环绕操作 com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod 2020-10-2413:36:33.488INFO12528---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:执行环绕操作结束,返回值:null 2020-10-2413:36:33.490INFO12528---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:执行环绕操作结束,返回值:null
开启暴露代理类,AopContext.currentProxy()方式获取代理类
通过暴露代理类方式,实际原理是把代理类添加到当前请求的ThreadLocal里面,然后在使用时从ThreadLocal中获取代理类,再调用对应的方法
在主方法上加入@EnableAspectJAutoProxy(exposeProxy=true),然后从AOP上下文中获取代理
@Override publicvoidtestAop(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop"+str); AopServiceImplservice=AopContext.currentProxy()!=null?(AopServiceImpl)AopContext.currentProxy():this; service.testAop2("testFinalMethod"); System.out.println(); }
2020-10-2413:38:31.031INFO18828---[nio-9000-exec-1]com.mantis.aop.controller.AopController:方法开始执行 2020-10-2413:38:31.035INFO18828---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:开始执行环绕操作 com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2 2020-10-2413:38:31.047INFO18828---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:开始执行环绕操作 com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod 2020-10-2413:38:31.048INFO18828---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:执行环绕操作结束,返回值:null 2020-10-2413:38:31.050INFO18828---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:执行环绕操作结束,返回值:null
2.final关键字问题
SpringAOP默认使用cglib,会生成目标对象的子类代理对象。调用目标对象的方法,实际上是调用代理对象的方法。由于子类能够继承父类的方法,因此一般情况下目标类的方法,代理对象都会有。但是当目标类中某个方法带有final关键字时,这个方法不能被重写,因此代理对象中没有这个方法,因此会调用目标对象的方法。
带final关键字
因为testFinalMethod方法中存在final关键字,导致无法重写,结果代理对象就无法生成这个方法,因此调用目标对象方法,导致没有被增强
@Override publicvoidtestAop(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop"+str); AopServiceImplservice=AopContext.currentProxy()!=null?(AopServiceImpl)AopContext.currentProxy():this; service.testFinalMethod("testFinalMethod"); System.out.println(); } publicfinalvoidtestFinalMethod(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod"+str); }
2020-10-2413:47:46.907INFO15204---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:开始执行环绕操作 com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2 com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethodtestFinalMethod 2020-10-2413:47:46.916INFO15204---[nio-9000-exec-1]com.mantis.aop.aspect.AopLog:执行环绕操作结束,返回值:null
不带final关键字
因为testFinalMethod方法中不存在final关键字,所以正常执行增强。
@Override publicvoidtestAop(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop"+str); AopServiceImplservice=AopContext.currentProxy()!=null?(AopServiceImpl)AopContext.currentProxy():this; service.testFinalMethod2("testFinalMethod"); System.out.println(); } publicfinalvoidtestFinalMethod2(Stringstr){ System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod"+str); }
2020-10-2413:50:51.018INFO13532---[nio-9000-exec-2]com.mantis.aop.controller.AopController:方法开始执行 2020-10-2413:50:51.021INFO13532---[nio-9000-exec-2]com.mantis.aop.aspect.AopLog:开始执行环绕操作 com.mantis.aop.service.AopService.AopServiceImpl.testAoptest2 2020-10-2413:50:51.029INFO13532---[nio-9000-exec-2]com.mantis.aop.aspect.AopLog:开始执行环绕操作 com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethodtestFinalMethod 2020-10-2413:50:51.030INFO13532---[nio-9000-exec-2]com.mantis.aop.aspect.AopLog:执行环绕操作结束,返回值:null 2020-10-2413:50:51.031INFO13532---[nio-9000-exec-2]com.mantis.aop.aspect.AopLog:执行环绕操作结束,返回值:null
总结
到此这篇关于SpringAOP使用时的一些问题汇总的文章就介绍到这了,更多相关SpringAOP使用时的问题内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!