Spring AOP使用入门案例

您所在的位置:网站首页 aop使用场景和案例 Spring AOP使用入门案例

Spring AOP使用入门案例

2024-07-12 21:21| 来源: 网络整理| 查看: 265

于AOP的原理网上有很多教程,此处不再赘述,只是通过具体的案例来记录如何使用。

一、入门案例

首先从start.spring.io上下载一个Spring Boot工程,只需要引入web依赖即可。然后我们创建一个Controller:

代码语言:javascript复制@RestController public class HelloController { /*@AspectAction(name = "loglog")*/ @GetMapping("/getHello") public String getHello(){ System.out.println("执行getHello!"); return "hello"; } }

然后创建一个切面:

代码语言:javascript复制@Aspect @Component public class LogAspect { /** * 前置通知 * 在方法执行之前执行 */ @Before("execution(* com.example.aopdemo.controller.HelloController.getHello(..))") public void before() { System.out.println("before"); } }

这个切面中最重要的就是@Before("execution(* com.example.aopdemo.controller.HelloController.getHello(..))"),它说明了这是一个前置通知,并且切入点为HelloController类中的getHello方法。

到这里一个最简单的AOP例子就能运行了,启动程序后,访问入口,打印信息如下:

代码语言:javascript复制before 执行getHello!二、通知类型

总共支持五种通知类型:

代码语言:javascript复制@Aspect @Component public class LogAspect { /** * 前置通知 * 在方法执行之前执行 */ @Before("execution(* com.example.aopdemo.controller.HelloController.getHello(..))") public void before() { System.out.println("before"); } /** * 后置通知 * 在方法执行之后 */ @After("execution(* com.example.aopdemo.controller.HelloController.getHello(..))") public void after() { System.out.println("after"); } /** * 返回通知 * 在方法执行之后,返回之前执行 */ @AfterReturning("execution(* com.example.aopdemo.controller.HelloController.getHello(..))") public void afterReturing(){ System.out.println("afterReturning"); } /** * 异常通知 * 在方法抛出异常之后执行 */ @AfterThrowing("execution(* com.example.aopdemo.controller.HelloController.getHello(..))") public void afterThrowing(){ System.out.println("afterThrowing"); } }

执行结果可以表现各个通知的执行顺序:

代码语言:javascript复制before 执行getHello! afterReturning after

还有一个环绕通知,可以代替其它四个通知,环绕通知可以实现其它四个通知。

代码语言:javascript复制 /** * 环绕通知 * 能够代替其它四种通知使用 */ @Around("execution(* com.example.aopdemo.controller.HelloController.getHello(..))") public void around(ProceedingJoinPoint joinPoint) { System.out.println("前置通知!"); try { // 执行目标方法中的逻辑 joinPoint.proceed(); System.out.println("返回通知!"); } catch (Throwable throwable) { System.out.println("异常通知!"); } finally { System.out.println("后置通知!"); } }

假设同时设置了四种通知,还有环绕通知,那么执行的顺序是怎样的呢?

代码语言:javascript复制前置通知! before 执行getHello! afterReturning after 返回通知! 后置通知!

需要注意的是,环绕通知中的joinPoint.proceed();如果不写的话,就会跳过切入点目标方法的逻辑执行,直接执行环绕通知后续的通知逻辑:

代码语言:javascript复制前置通知! 返回通知! 后置通知!三、切点表达式

在如上的案例中,我们发现如果定义了很多通知,在定义切入点表达式时写了很多一样的东西:

代码语言:javascript复制"execution(* com.example.aopdemo.controller.HelloController.getHello(..))"

其实可以在切面类中先定义一个切点表达式,然后其它通知定义的时候引用这个切点表达式即可:

代码语言:javascript复制@Aspect @Component public class LogAspect { /** * 声明切点表达式 */ @Pointcut("execution(* com.example.aopdemo.controller.HelloController.getHello(..))") public void pointCut(){} /** * 环绕通知 * 能够代替其它四种通知使用 */ @Around("pointCut()") public void around(ProceedingJoinPoint joinPoint) { System.out.println("前置通知!"); try { //joinPoint.proceed(); System.out.println("返回通知!"); } catch (Throwable throwable) { System.out.println("异常通知!"); } finally { System.out.println("后置通知!"); } } }四、切点指示器

以上面的切点表达式为例:

execution表示匹配执行目标方法,还有其它类型的指示器,但用的不多;*表示不关心方法的返回值;..表示不关心方法的参数; 如果需要多个匹配条件可以使用&& || !来表示且、或、非的关系; @Before("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..)) && within(com.sharpcj.aopdemo.test1.*) && bean(girl)") 其中within是和execution平行的指示器,表示匹配的切入点类型;bean是实例匹配器,只有遇到girl这个实例的时候才会执行AOP; 五、使自定义注解

有的时候我们希望在声明自定义注解的方法上执行AOP的逻辑,而不是如上指定具体的位置。

首先我们需要先定义自己的注解:

代码语言:javascript复制@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AspectAction { String name() default "default"; }

然后,在切面中定义切入点为标注这个注解的地方。

代码语言:javascript复制@Aspect @Component public class LogAspect { @Pointcut("@annotation(com.example.aopdemo.annotation.AspectAction)") public void pointCut(){} @Around("pointCut()") public void around(ProceedingJoinPoint joinPoint) { System.out.println("前置通知!"); try { joinPoint.proceed(); System.out.println("返回通知!"); } catch (Throwable throwable) { System.out.println("异常通知!"); } finally { System.out.println("后置通知!"); } } }

最后,只要在想使用AOP的方法之上加上自定义注解即可:

代码语言:javascript复制@AspectAction(name = "loglog") @GetMapping("/getHello") public String getHello(){ System.out.println("执行getHello!"); return "hello"; }

我们在环绕通知中,可以通过ProceedingJoinPoint来获取如下各种信息,ProceedingJoinPoint继承自JoinPoint,所以在其它类型的通知中也可以获得如下内容:



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3