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

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

切面记录日志

切面类

@Slf4j
@Aspect
@Component
public class AspectForFeign {
    
    @Pointcut("execution(public * com.keke.remote..*Feign.*(..))")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        log.info("@Around:开始执行目标方法:{}ms", start);
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        long end = System.currentTimeMillis();
        log.info("@Around:结束执行目标方法:{}ms", end);
        //获取方法签名 
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getName();
        log.info("方法名:{} 耗时:{}ms", methodName, end - start);
        //如果不返回result,则目标对象实际返回值会被置为null
        return result;
    }
  • 注意:返回结果如果不返回result,则目标对象实际返回值会被置为null

@Component

  • 需要将切面类配置为bean

@Aspect

  • 标记为切面类

@Pointcut

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

@Around

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

切点拦截记录访问日志

拦截器数据源

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

拦截器业务实现代码

@Aspect
@Component
@Slf4j
public class ApiAccessAspect {

    @Pointcut("@annotation(com.keke.annotation.ApiAccess)")
    public void pointcut() {}

    @Around("pointcut()")
    public Object apiAccessAspect(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        log.info("url:{}被访问了.....",request.getRequestURL().toString());
        return joinPoint.proceed(joinPoint.getArgs());
    }
}

@Pointcut的表达式-@annotation

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

官方案例:

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

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

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

看案例:

我们准备接口:

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

实现类:

/** * @description */
@Component
public class BookService implements IBookService{
    @Override
    @DkAnnotation //这里的注解会被匹配
    public void saveBook(String title){
        System.out.println("保存图书:"+title);
    }
    public void saveBook(String title,int count){
        System.out.println("保存"+title+","+count+"次");
    }
}

修改Aspect类:

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

测试:

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

结果:

相关文章