切面记录日志
切面类
@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,则目标对象实际返回值会被置为nullreturn 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("---前置通知---");}
}
测试:
@Testpublic void testAopPoint_annotation(){ApplicationContext ac =new AnnotationConfigApplicationContext(Appconfig.class);IBookService bean = ac.getBean(IBookService.class);bean.saveBook("程序员的修养");}
结果: