springboot 实现 AOP 切面编程
AOP 的通知类型
前置通知 : 在目标类的方法执行之前执行。
配置文件信息:<aop: before method=“before” pointcut-ref=“myPointcut3”/>
应用:可以对方法的参数来做校验
最终通知 : 在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
在配置文件中编写具体的配置:<aop:after method=“after” pointcut-ref=“myPointcut3”/>
应用:例如像释放资源
后置通知 : 方法正常执行后的通知。
在配置文件中编写具体的配置:<aop:after-returning method=“afterReturning” pointcut-ref=“myPointcut2”/>
应用:可以修改方法的返回值
异常抛出通知 : 在抛出异常后通知
在配置文件中编写具体的配置:<aop:after-throwing method=“afterThorwing” pointcut-ref=“myPointcut3”/>
应用:包装异常的信息
环绕通知: 方法的执行前后执行。环绕通知使用灵活.其他方式都能用环绕方式实现。
在配置文件中编写具体的配置:<aop:around method=“around” pointcut-ref=“myPointcut2”/>
要注意:目标的方法默认不执行,需要使用 ProceedingJoinPoint 对来让目标对象的方法执行。
使用 aspectj 实现 AOP 功能
在 pom.xml 中引入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
方式一:
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
//注解表明这是一个 AspectJ 文件,编译器在编译的时候,就会自动去解析,然后将代码注入到相应的 JPonit 中。
@Aspect //必须的注解
@Order(-1)
public class AOPDemo {
@Pointcut(value = "execution(* com.controller.update(..))")
private void beforePointcut(){
//切面,方法里的内容不会执行
}
@Before(value = "beforePointcut()")
public void before(JoinPoint joinPoint){
//@Before 是在方法执行前无法终止原方法执行
System.out.println("前置通知。。。"+
joinPoint);
}
@Pointcut(value = "execution(* com.controller.save(..))")
private void afterReturningPointcut(){}
@AfterReturning(value = "afterReturningPointcut()",returning = "result")
public void afterReturning(Object result){
System.out.println("后置通知。。。"+result);
}
@Pointcut(value = "execution(* com.controller.delete(..))")
private void aroundPointcut(){}
@Around(value = "aroundPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//用 @Around 用环绕通知可以拒绝可以放行
System.out.println("环绕通知。。。");
Object obj = joinPoint.proceed();
System.out.println("环绕通知。。。");
return obj;
}
@Pointcut(value = "execution(* com.controller.findOne(..))")
private void afterThrowingPointcut(){}
@AfterThrowing(value = "afterThrowingPointcut()",throwing = "e")
public void afterThrowing(Throwable e){
System.out.println("异常抛出通知"+e.getMessage());
}
@Pointcut(value = "execution(* com.controller.findAll(..))")
private void afterPointcut(){}
//|| 关联多个切面
@After(value = "afterPointcut() || afterReturningPointcut()")
public void after(){
System.out.println("最终通知");
}
}
execution: 处理 JPoint 的类型,例如 call,execution
例如定义切入点表达式 execution (* com.sample.service.impl…*. *(…)) 整个表达式可以分为五个部分:
1、execution(): 表达式主体。
2、第一个*号:表示返回类型, *号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl 包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
_多个切点例如:
@Before("execution (_ android.app.Activity.onCreate(…)) ||execution (* android.app.Activity.onDestroy()) "
JoinPoint 对象
JoinPoint 对象封装了 SpringAop 中切面方法的信息,在切面方法中添加 JoinPoint 参数,就可以获取到封装了该方法信息的 JoinPoint 对象.
常用 api:
Signature getSignature(); 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类
Class等信息
Object[] getArgs(); 获取传入目标方法的参数对象
Object getTarget(); 获取被代理的对象
Object getThis(); 获取代理对象
ProceedingJoinPoint 对象
ProceedingJoinPoint 对象是 JoinPoint 的子接口,该对象只用在 @Around 的切面方法中,
评论