AOP名词基础概念
- 切面(Aspect)
AOP思想就是面向切面编程,对一个我们已经封装好的类,我们可以在运行的各个时期,对其进行切割,在原有的方法中织入一些新的代码,不改变原有方法的功能,只做增强,而那些增强部分的代码,就被称为切面。常常用于权限认证,日志,事务处理等。 - 切入点(PointCut)
所谓切入点,就是那个类中的那个方法进行增强,进行切割,指被增强的方法,就是要切的东西。 - 连接点(JoinPoint)
在我们知道要切入那些方法之后,就需要知道在什么时候切入,比如在方法被调用之前,调用之后,发生异常等时候调用。 - 通知(advice)
所谓的通知,就是通知被织入的方法,应该如何增强。
其中@Pointcut注解为指明切入点,@Before,@After是连接点,注解对应下面的就是对应的通知。 - 目标对象(Target Object)
被一个或者多个切面通知的对象,就是目标对象。 - 织入(Weaving)
所谓织入,就是将切面切入到目标方法中,使得目标方法被增强的过程。
常用注解解释
@Aspect: 作用是把当前类标识为一个切面供容器读取
@Pointcut: 是声明切入点,Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
@Around:环绕增强,相当于MethodInterceptor
@AfterReturning:后置增强,方法执行之后再执行,相当于AfterReturningAdvice,方法正常退出时执行
@Before:前置增强方法,方法执行之前执行,相当于BeforeAdvice的功能,相似功能的还有
@AfterThrowing:异常抛出增强,相当于ThrowsAdvice
@After: 最终通知(在目标方法执行后调用,无论目标方法是否出现异常,都会执行),不管是抛出异常或者正常退出都会执行
使用方法
1:引入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2:自定义通知注解(本次用一个运行前注解样例)
@Target({ElementType.METHOD})//作用在方法上
@Retention(RetentionPolicy.RUNTIME)//运行时
public @interface Refresh {
int type() default 1;
}
切面代码
@Aspect
@Component
public class RefreshAspect {
/**
* 环绕通知
* Pointcut:切入点
*/
@Pointcut("@annotation(com.xxy.gps.annotation.Refresh)")
private void around() {
}
@Around("around()")
private Object testAop(ProceedingJoinPoint point) throws Throwable {
System.out.println("======AopAspectJ执行环绕通知开始=========");
Object obj = point.proceed();
Object[] args = point.getArgs();
//方法名
String methodName = point.getSignature().getName();
//对象
Object target = point.getTarget();
//类名
String className = target.getClass().getName();
System.out.println("类:" + className + ";方法:" + methodName + ";参数:" + JSONArray.toJSONString(args));
System.out.println("======AopAspectJ执行环绕通知结束=========");
return obj;
}
/**
* 前置通知
*/
@Before("@annotation(refresh)")
public void beforeAdvance(Refresh refresh) {
System.out.println("======AopAspectJ执行前置通知=========");
}
/**
* 后置通知(在目标方法执行后调用,若目标方法出现异常,则不执行)
*/
@AfterReturning("@annotation(refresh)")
private void afterRunningAdvance(Refresh refresh) {
System.out.println("type=" + refresh.type());
System.out.println("======AopAspectJ执行后置通知=========");
}
/**
* 最终通知(在目标方法执行后调用,无论目标方法是否出现异常,都会执行)
*/
@Pointcut("@annotation(com.xxy.gps.annotation.Refresh)")
private void after() {
}
@After("after()")
public void afterAdvance() {
System.out.println("======AopAspectJ执行最终通知=========");
}
/**
* 异常通知:目标方法抛出异常时执行
*/
@AfterThrowing("@annotation(refresh)")
public void afterThrowingAdvance(Refresh refresh) {
System.out.println("======AopAspectJ执行异常通知=========");
}
}
测试
@Component
public class MyTest {
@Refresh
public void log() {
System.err.println("输出日志");
}
}
@SpringBootTest
class GpsServiceApplicationTests {
@Autowired
private MyTest myTest;
@Test
void contextLoads() {
myTest.log();
}
}