SpringAop @Pointcut(“@annotation“)\@Aspect练习

x33g5p2x  于2021-12-08 转载在 Spring  
字(2.9k)|赞(0)|评价(0)|浏览(395)

切面记录日志

切面类

  1. @Slf4j
  2. @Aspect
  3. @Component
  4. public class AspectForFeign {
  5. @Pointcut("execution(public * com.keke.remote..*Feign.*(..))")
  6. public void pointcut() {
  7. }
  8. @Around("pointcut()")
  9. public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
  10. long start = System.currentTimeMillis();
  11. log.info("@Around:开始执行目标方法:{}ms", start);
  12. Object result = null;
  13. try {
  14. result = joinPoint.proceed();
  15. } catch (Exception e) {
  16. System.out.println(e.getMessage());
  17. }
  18. long end = System.currentTimeMillis();
  19. log.info("@Around:结束执行目标方法:{}ms", end);
  20. //获取方法签名
  21. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  22. String methodName = methodSignature.getName();
  23. log.info("方法名:{} 耗时:{}ms", methodName, end - start);
  24. //如果不返回result,则目标对象实际返回值会被置为null
  25. return result;
  26. }
  • 注意:返回结果如果不返回result,则目标对象实际返回值会被置为null

@Component

  • 需要将切面类配置为bean

@Aspect

  • 标记为切面类

@Pointcut

  • 需要表达式命名,而不需要在方法体内编写实际代码。
  1. execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

@Around

  • 环绕增强,@Pointcut和@Around联合使用等同于:
  1. @Around("execution(public * com.keke.remote..*Feign.*(..))")

切点拦截记录访问日志

拦截器数据源

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.METHOD)//注解在方法上
  3. public @interface ApiAccess{
  4. }

拦截器业务实现代码

  1. @Aspect
  2. @Component
  3. @Slf4j
  4. public class ApiAccessAspect {
  5. @Pointcut("@annotation(com.keke.annotation.ApiAccess)")
  6. public void pointcut() {}
  7. @Around("pointcut()")
  8. public Object apiAccessAspect(ProceedingJoinPoint joinPoint) throws Throwable {
  9. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  10. log.info("url:{}被访问了.....",request.getRequestURL().toString());
  11. return joinPoint.proceed(joinPoint.getArgs());
  12. }
  13. }

@Pointcut的表达式-@annotation

限制连接点的匹配,其中连接点的主题(在 Spring AOP 中执行的方法)具有给定的 annotation。

官方案例:

任何连接点(仅在 Spring AOP 中执行方法),其中执行方法具有@Transactional annotation:

  1. @annotation(org.springframework.transaction.annotation.Transactional)

官方的案例已经说的很清楚了,就是@annotation是匹配拥有指定注解的方法的。这里要注意,@annotation只匹配实现类中的有注解的方法,不会匹配接口中的注解方法。

看案例:

我们准备接口:

  1. /** * @description */
  2. public interface IBookService {
  3. //@DkAnnotation// 这里的注解是不会被匹配的
  4. public void saveBook(String title);
  5. }

实现类:

  1. /** * @description */
  2. @Component
  3. public class BookService implements IBookService{
  4. @Override
  5. @DkAnnotation //这里的注解会被匹配
  6. public void saveBook(String title){
  7. System.out.println("保存图书:"+title);
  8. }
  9. public void saveBook(String title,int count){
  10. System.out.println("保存"+title+","+count+"次");
  11. }
  12. }

修改Aspect类:

  1. /** * @description */
  2. @Component //将当前bean交给spring管理
  3. @Aspect //定义为一个AspectBean
  4. public class DkAspect {
  5. //使用@annotation配置匹配所有还有指定注解的方法
  6. @Pointcut("@annotation(com.st.dk.demo7.annotations.DkAnnotation)")
  7. private void pointCut1(){}
  8. //定义一个前置通知
  9. @Before("pointCut1()")
  10. private static void befor(){
  11. System.out.println("---前置通知---");
  12. }
  13. }

测试:

  1. @Test
  2. public void testAopPoint_annotation(){
  3. ApplicationContext ac =
  4. new AnnotationConfigApplicationContext(Appconfig.class);
  5. IBookService bean = ac.getBean(IBookService.class);
  6. bean.saveBook("程序员的修养");
  7. }

结果:

相关文章