有时候,我们使用AOP来进行放的增强,编写切面类的时候,需要定位在哪个方法上试用该切面进行增强,本片文章主要讲解两种在SpringBoot中定位切点的方法,一种是使用execution表达式的方法,一种则是利用自定义注解的方法。
接下来以一个简单的例子来讲解这两种方法的使用方式。
<==========方法执行前==========>
method();
<==========方法执行后==========>
execution 表达式
execution表达式的方式主要是在定义切点的时候,通过表达式的方式选取到所需要增强的方法。
execution表达式解读
execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
类型 | 解读 | 是否必须 | 示例 |
---|---|---|---|
<修饰符模式> | 表示所选的修饰符类型 | 否 | public/private/... |
<返回类型模式> | 表示所选的返回值类型 | 是 | void/int/... |
<方法名模式> | 表示所选的包或者方法 | 是 | com.luke.service/com.luke.controller.*/... |
(<参数模式>) | 表示所选方法的参数 | 是 | *(..)/*(String name)/*(int size, ..)/... |
<异常模式> | 表示所选方法的异常类型 | 否 | throws Exception/... |
// 匹配指定包中的所有方法 execution(* com.luke.service.*(..)) // 匹配当前包中的所有public方法 execution(public * UserService.*(..)) // 匹配指定包中的所有public方法,并且返回值是int类型的方法 execution(public int com.luke.service.*(..)) // 匹配指定包中的所有public方法,并且第一个参数是String,返回值是int类型的方法 execution(public int com.luke.service.*(String name, ..))
自定义切面类:
@Aspect @Component public class LogAspect { @Pointcut("execution(* com.luke.springdata.controller.*.*(..))") public void operationLog(){} /** * 这里只定义一个Around的增强做展示 */ @Around("operationLog()") public Object doAround(ProceedingJoinPoint joinPoint) { Object proceed = null; try { System.out.println("方法执行前"); proceed = joinPoint.proceed(); System.out.println("方法执行后"); } catch (Throwable throwable) { throwable.printStackTrace(); } return proceed; } }
此切点的execution表达式为com.luke.springdata.controller包下的所有方法。
使用**@Around**注解表明增强的方法,并且指定切点。
测试用Controller类
@RestController @RequestMapping("/person") public class PersonController { @GetMapping("/test") public void test(){ System.out.println("方法执行了"); } }
运行项目,调用该方法,查看结果。
方法执行前
方法执行了
方法执行后
自定义注解的方法
自定义注解的方式就是在需要增强的方法上面加上自定义的注解即可。
自定义注解类:
@Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Log{ }
这里自定义了一个注解Log,该注解只能加在方法上。
自定义切面类:
@Aspect @Component public class LogAspect { @Pointcut("@annotation(com.luke.springdata.annotation.Log)") public void operationLog(){} /** * 这里只定义一个Around的增强做展示 */ @Around("operationLog()") public Object doAround(ProceedingJoinPoint joinPoint) { Object proceed = null; try { System.out.println("方法执行前"); proceed = joinPoint.proceed(); System.out.println("方法执行后"); } catch (Throwable throwable) { throwable.printStackTrace(); } return proceed; } }
这里编写的自定义个切面类,用**@Pointcut注解定义一个切面,并且这次采用@annotation(xxx)**的方式表明如果哪个方法上添加了xxx注解,则就使用该切面做增强。
同时在每个增强的方法上使用该切面,随后编写正常的方法增强逻辑即可。
测试用Controller类
@RestController @RequestMapping("/person") public class PersonController { @Log @GetMapping("/test") public void test(){ System.out.println("方法执行了"); } }
此时在需要使用切面的方法上加入**@Log**注解,调用该方法,查看效果。
方法执行前
方法执行了
方法执行后
总结
两种方式均能实现AOP的功能,在使用上,如果某个包下面的所有方法,都需要这个切面进行增强,那么使用execution表达式的方式更方便。但如果只有部分方法需要,并且分布在不同的类中,则注解的方式更灵活。