前言:AspectJ 不是 Spring框架的组成部分,是独立的AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用进行 AOP 操作
比如某个类中有如下4个方法:
Class A{
add();
delete();
update();
select();
}
类A中的4个方法都可能被增强,这4个方法成为连接点
如果我实际只增强 add()和update()方法,则add()和update()称为切入点;
即实际被真正增强方法
比如我增强add()方法,在add()方法执行之前加上判断代码,这个判断代码就称为通知;
即实际增强的逻辑部分称为通知或增强
通知的五种类型:
切面是一个动作,把我们的通知应用到切入点的过程叫做切面。
比如把判断代码加到add()方法之前的这个过程称为切面。
切入点表达式的作用是知道对哪个类里面的哪个方法进行增强。
execution([权限修饰符][返回值类型][类全路径][方法名称]([参数列表])[异常])
其中返回值类型、方法名称和参数列表是必填的。
举例 1:对 aop.annotation.Student 类里面的 eat方法进行增强 execution(public void aop.annotation.Student.eat(…))
举例 2:对 aop.annotation.Student 类里面的所有的方法进行增强 execution(* aop.annotation.Student.* (…))
举例 3:对 aop.annotation 包里面所有类,类里面所有方法进行增强 execution(* aop.annotation.. (…))
StudentProxy类:
@Component
@Aspect
public class StudentProxy {
//前置通知
@Before(value = "execution(public void aop.annotation.Student.eat(..))")
public void beforeDemo(){
System.out.println("饿了!");
}
//后置通知(返回通知)
@AfterReturning("execution(* aop.annotation.Student.*(..))")
public void afterReturningDemo(){
System.out.println("饭后甜点");
}
//最终通知
@After(value = "execution(void aop.annotation.Student.eat(..))")
public void afterDemo(){
System.out.println("饱了!");
}
//异常通知
@AfterThrowing("execution(void aop.annotation.Student.eat(..))")
public void afterThrowingDemo(){
System.out.println("噎住了!");
}
//环绕通知
@Around("execution(* aop.annotation.Student.*(..))")
public void aroundDemo(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("吃饭前...");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("吃饭后...");
}
}
Student类:
@Component
public class Student {
public void eat(){
System.out.println("eat something!");
}
}
xml配置文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="aop.annotation">context:component-scan>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
beans>
测试类:
public class DemoTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("aop/annotation/bean.xml");
Student student = context.getBean("student", Student.class);
student.eat();
}
}
输出结果:
吃饭前...
饿了!
eat something!
饭后甜点
饱了!
吃饭后...
Process finished with exit code 0
更改Student中代码,让其报错,如下:
@Component
public class Student {
public void eat(){
int i = 1/0;
System.out.println("eat something!");
}
}
pointDemo方法上使用@Pointcut注解,把上述代码中的前置通知的切入点表达式用pointDemo方法替换;
同理其他的切入点表达式都可以用其替换,方便开发。
//相同切入点抽取
@Pointcut(value = "execution(* aop.annotation.Student.eat(..))")
public void pointDemo(){
}
//前置通知
@Before(value = "pointDemo()")
public void beforeDemo(){
System.out.println("饿了!");
}
当有多个增强类对同一个方法进行增强时,可以使用@Order(数字类型值)注解来进行优先级设置,数字类型值越小,优先级越高,越优先执行。
在创建一个StudentOneProxy类对Student类中对eat方法进行增强,设置@Order(2),StudentOneProxy如下:
@Component
@Aspect
@Order(2)
public class StudentOneProxy {
@Before("execution(* aop.annotation.Student.eat(..))")
public void BeforeDemo(){
System.out.println("StudentOneProxy.BeforeDemo...");
}
@Around("execution(* aop.annotation.Student.eat(..))")
public void aroundDemo(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("StudentOneProxy.Around...");
proceedingJoinPoint.proceed();
System.out.println("StudentOneProxy.Around...");
}
}
在StudentProxy类上添加@Order(1)注解,截图如下:
输出结果:
吃饭前...
饿了!
StudentOneProxy.Around...
StudentOneProxy.BeforeDemo...
eat something!
StudentOneProxy.Around...
饭后甜点
饱了!
吃饭后...
Process finished with exit code 0
可以看到设置为@Order(1)的Student类先执行。