java怎么拦截某个对象
255
2022-09-04
[Spring Framework]AOP配置管理③(AOP通知获取数据)
文章目录
AOP通知获取数据
项目环境获取切入点方法的参数
非环绕通知获取方式环绕通知获取方式
获取返回值
环绕通知获取返回值返回后通知获取返回值
获取异常
环绕通知获取异常抛出异常后通知获取异常
AOP通知获取数据
目前我们写AOP仅仅是在原始方法前后追加一些操作,接下来我们要说说AOP中数据相关的内容,我们将从以下三个方面来研究切入点的相关信息:
获取参数获取返回值获取异常
前面我们介绍通知类型的时候总共讲了五种,那么对于这五种类型都会有参数,返回值和异常吗?
我们先来一个个分析下:
获取切入点方法的参数,所有的通知类型都可以获取参数
JoinPoint:适用于前置、后置、返回后、抛出异常后通知ProceedingJoinPoint:适用于环绕通知
获取切入点方法返回值,前置和抛出异常后通知是没有返回值,后置通知可有可无,所以不做研究,我们主要讨论:
返回后通知环绕通知
获取切入点方法运行异常信息,前置和返回后通知是不会有,后置通知可有可无,所以不做研究,我们只讨论:
抛出异常后通知环绕通知
项目环境
首先我们准备,一个接口以及其实现类:
public interface BookDao { public String findName(int id);}@Repositorypublic class BookDaoImpl implements BookDao { public String findName(int id) { System.out.println("id:"+id); return "CSDN"; }}
通知类:
@Component@Aspectpublic class MyAdvice2 { @Pointcut("execution(* *BookDao4.findName(..))") private void pt(){} @Before("pt()") public void before() { System.out.println("before advice ..." ); } @After("pt()") public void after() { System.out.println("after advice ..."); } @Around("pt()") public Object around() throws Throwable{ Object ret = pjp.proceed(); return ret; } @AfterReturning("pt()") public void afterReturning() { System.out.println("afterReturning advice ..."); } @AfterThrowing("pt()") public void afterThrowing() { System.out.println("afterThrowing advice ..."); }}
然后我们的测试demo:
public class App12 { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); BookDao4 bookDao = ctx.getBean(BookDao4.class); String name = bookDao.findName(100); System.out.println(name); }}
获取切入点方法的参数
因为所有的通知类型都可以获取切入点方法的参数,所以这里我们分为两种来讨论:
非环绕通知获取方式环绕通知获取方式
非环绕通知获取方式
核心操作:在方法上添加JoinPoint,通过JoinPoint来获取参数
@Component@Aspectpublic class MyAdvice2 { @Pointcut("execution(* *.BookDao4.findName(..))") private void pt(){} @Before("pt()") public void before(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); System.out.println(Arrays.toString(args)); System.out.println("before advice ..." ); } //...其他的略}
结果:
这里使用一个Object数组是因为参数个数不确定,参数类型也不确定,我们再在原切入点方法中添加一个参数看看效果:
运行结果:
说明: 使用JoinPoint的方式获取参数适用于前置、后置、返回后、抛出异常后通知。
环绕通知获取方式
环绕通知使用的是ProceedingJoinPoint,因为ProceedingJoinPoint是JoinPoint类的子类,所以对于ProceedingJoinPoint类中应该也会有对应的getArgs()方法,我们去验证下:
@Component@Aspectpublic class MyAdvice { @Pointcut("execution(* *.BookDao4.findName(..))") private void pt(){} @Around("pt()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ Object[] args = proceedingJoinPoint.getArgs(); Object proceed = proceedingJoinPoint.proceed(); System.out.println("around advice ..."); System.out.println(Arrays.toString(args)); return proceed; } //其他的略}
执行结果:
注意:
调用无参数的proceed,当原始方法有参数,会在调用的过程中自动传入参数所以调用这两个方法的任意一个都可以完成功能但是当需要修改原始方法的参数时,就只能采用带有参数的方法,如下:
@Component@Aspectpublic class MyAdvice { @Pointcut("execution(* *.BookDao4.findName(..))") private void pt(){} @Around("pt()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ Object[] args = proceedingJoinPoint.getArgs(); args[0] = 666; Object proceed = proceedingJoinPoint.proceed(args); System.out.println("around advice ..."); System.out.println(Arrays.toString(args)); return proceed; } //其他的略}
结果:
有了这个特性后,我们就可以在环绕通知中对原始方法的参数进行拦截过滤,避免由于参数的问题导致程序无法正确运行,保证代码的健壮性。
获取返回值
对于返回值,只有返回后AfterReturing和环绕Around这两个通知类型可以获取,具体如何获取?
环绕通知获取返回值
@Component @Aspect public class MyAdvice { @Pointcut("execution(* *.BookDao4.findName(..))") private void pt(){} @Around("pt()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ Object[] args = proceedingJoinPoint.getArgs(); args[0] = 666; Object proceed = proceedingJoinPoint.proceed(args); System.out.println("around advice ..."); System.out.println(Arrays.toString(args)); return proceed; } //其他的略 }
上述代码中,proceed就是方法的返回值,我们是可以直接获取,不但可以获取,如果需要还可以进行修改。
返回后通知获取返回值
@Component@Aspectpublic class MyAdvice { @Pointcut("execution(* *.BookDao4.findName(..))") private void pt(){} @AfterReturning(value = "pt()",returning = "str") public void afterReturning(Object str) { System.out.println(str); System.out.println("afterReturning advice ..."); } //其他的略}
结果;
注意:
(1)参数名的问题
(2)afterReturning方法参数类型的问题
参数类型可以写成String,但是为了能匹配更多的参数类型,建议写成Object类型
(3)afterReturning方法参数的顺序问题
获取异常
对于获取抛出的异常,只有抛出异常后AfterThrowing和环绕Around这两个通知类型可以获取,具体如何获取?
环绕通知获取异常
这块比较简单,以前我们是抛出异常,现在只需要将异常捕获,就可以获取到原始方法的异常信息了
@Component@Aspectpublic class MyAdvice { @Pointcut("execution(* *.BookDao4.findName(..))") private void pt(){} @Around("pt()") public Object around(ProceedingJoinPoint proceedingJoinPoint) { Object[] args = proceedingJoinPoint.getArgs(); args[0] = 666; Object proceed = null; try { proceed = proceedingJoinPoint.proceed(args); } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("around advice ..."); System.out.println(Arrays.toString(args)); return proceed; } //其他的略}
在catch方法中就可以获取到异常,至于获取到异常以后该如何处理,这个就和你的业务需求有关了。
抛出异常后通知获取异常
@Component@Aspectpublic class MyAdvice { @Pointcut("execution(* *.BookDao4.findName(..))") private void pt(){} @AfterThrowing(value = "pt()",throwing = "t") public void afterThrowing(Throwable t) { System.out.println(t); System.out.println("afterThrowing advice ..."); } //其他的略}
如何让原始方法抛出异常,方式有很多:
最后的结果:
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~