springboot AOP实战
AOP实战
maven依赖
引入aop的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
定义切面
采用扫描类的方式
将切点定义在AppService这个类的所有方法上
@Pointcut("execution(public * com.lexiaoyao.aopdemo.service.AppService.*(..)))")
public void BrokerAspect() {
}
采用注解的方式
首先需要定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
String value() default "";
}
然后定义切面
@Pointcut("@annotation(com.lexiaoyao.aopdemo.Ann)")
public void otherAspect() {
}
通知
在通知执行和业务分离的逻辑
前置通知
在方法执行前执行
@Before("BrokerAspect()")
public void doBeforeGame(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Class<?> aClass = joinPoint.getTarget().getClass();
System.out.println(aClass.getName());
System.out.println(methodName);
System.out.println("前置增强");
}
后置通知
在方法执行后执行
@After("BrokerAspect()")
public void doAfterGame(JoinPoint joinPoint) {
System.out.println("后置增强");
}
返回通知
可获取方法的返回值,通过returning接受返回值
@AfterReturning(value = "BrokerAspect()", returning = "returnValue")
public void logMethodCall(JoinPoint jp, Object returnValue) throws Throwable {
System.out.println("进入后置增强了!");
String name = jp.getSignature().getName();
System.out.println(name);
Object[] args = jp.getArgs();
for (Object arg : args) {
System.out.println("参数:" + arg);
}
System.out.println("方法返回值为:" + returnValue);
}
异常通知
在切面处捕获方法抛出的异常
@AfterThrowing("BrokerAspect()")
public void doAfterThrowingGame(JoinPoint joinPoint) {
System.out.println("捕获异常");
}
环绕通知
环绕通知的功能最强大,可以包含上述所有的通知。
@Around("otherAspect()")
public void doAroundGameData(ProceedingJoinPoint pjp) throws Throwable {
try {
Object[] args = pjp.getArgs();//获取参数
MethodSignature signature = (MethodSignature) pjp.getSignature();
String name = signature.getMethod().getName();//获取方法名
Ann declaredAnnotation = getDeclaredAnnotation(pjp);//获取注解
System.out.println(declaredAnnotation.value());
System.out.println(name);//前置增强
Object proceed = pjp.proceed();//获取返回值
System.out.println(proceed);//后置增强
} catch (Throwable e) {
//在切面里可以捕获切点抛出的异常
System.out.println("异常通知");
}
}
JoinPoint
每个通知方法都可以放置JoinPoint变量。
JoinPoint是一个接口,常用两个实现类。
MethodInvocationProceedingJoinPoint是除了环绕通知的JoinPoint的实现类。‘
主要实现的方法为获取类名和方法名
// 获取方法名
String methodName = joinPoint.getSignature().getName();
// 反射获取目标类
Class<?> targetClass = joinPoint.getTarget().getClass();
ProceedingJoinPoint是环绕通知的JoinPoint实现类
通知方法中可以做任何的事情,当要将控制权交给被通知的方法时,需要调用ProceedingJoinPoint的proceed()方法。当你不调用proceed()方法时,将会阻塞被通知方法的访问。
获取切点处的注解
public Ann getDeclaredAnnotation(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
// 获取方法名
String methodName = joinPoint.getSignature().getName();
// 反射获`取目标类
Class<?> targetClass = joinPoint.getTarget().getClass();
// 拿到方法对应的参数类型
Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
// 根据类、方法、参数类型(重载)获取到方法的具体信息
Method objMethod = targetClass.getMethod(methodName, parameterTypes);
// 拿到方法定义的注解信息
Ann annotation = objMethod.getDeclaredAnnotation(Ann.class);
// 返回
return annotation;
}