基于AspectJ实现AOP操作
前言:AspectJ 不是 Spring框架的组成部分,是独立的AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用进行 AOP 操作
一.AOP相关术语
比如某个类中有如下4个方法:
Class A{
add();
delete();
update();
select();
}
- 1
- 2
- 3
- 4
- 5
- 6
1.连接点(JoinPoint)
类A中的4个方法都可能被增强,这4个方法成为连接点
2.切入点(PointCut)
如果我实际只增强 add()和update()方法,则add()和update()称为切入点;
即实际被真正增强方法
3.通知、增强(Advice)
比如我增强add()方法,在add()方法执行之前加上判断代码,这个判断代码就称为通知;
即实际增强的逻辑部分称为通知或增强
通知的五种类型:
- 前置通知 :在执行add()方法之前有一些逻辑部分
- 后置通知(返回通知):在执行add()方法之后有一些逻辑部分
- 环绕通知:在执行add()方法之前和之后都有一些逻辑部分
- 异常通知:当执行add()方法出现异常时会执行的逻辑部分
- 最终通知:与try-catch-finally中的finally类似,最终一定会执行的逻辑部分
4.切面(Aspect)
切面是一个动作,把我们的通知应用到切入点的过程叫做切面。
比如把判断代码加到add()方法之前的这个过程称为切面。
二.切入点表达式
切入点表达式的作用是知道对哪个类里面的哪个方法进行增强。
1.切入点表达式的格式
execution([权限修饰符][返回值类型][类全路径][方法名称]([参数列表])[异常])
其中返回值类型、方法名称和参数列表是必填的。
2.切入点表达式通配符:
- *:匹配所有字符
- …:一般用于匹配多个包,多个参数
- +:表示类及其子类
举例 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.. (…))
3.代码示例:
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("吃饭后...");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
Student类:
@Component
public class Student {
public void eat(){
System.out.println("eat something!");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
测试类:
public class DemoTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("aop/annotation/bean.xml");
Student student = context.getBean("student", Student.class);
student.eat();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
输出结果:
吃饭前...
饿了!
eat something!
饭后甜点
饱了!
吃饭后...
Process finished with exit code 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
更改Student中代码,让其报错,如下:
@Component
public class Student {
public void eat(){
int i = 1/0;
System.out.println("eat something!");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
输出结果:
4.相同切入点抽取
pointDemo方法上使用@Pointcut注解,把上述代码中的前置通知的切入点表达式用pointDemo方法替换;
同理其他的切入点表达式都可以用其替换,方便开发。
//相同切入点抽取
@Pointcut(value = "execution(* aop.annotation.Student.eat(..))")
public void pointDemo(){
}
//前置通知
@Before(value = "pointDemo()")
public void beforeDemo(){
System.out.println("饿了!");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
5.@Order(数字类型值)注解
当有多个增强类对同一个方法进行增强时,可以使用@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...");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
在StudentProxy类上添加@Order(1)注解,截图如下:
输出结果:
吃饭前...
饿了!
StudentOneProxy.Around...
StudentOneProxy.BeforeDemo...
eat something!
StudentOneProxy.Around...
饭后甜点
饱了!
吃饭后...
Process finished with exit code 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
可以看到设置为@Order(1)的Student类先执行。
文章来源: blog.csdn.net,作者:Mr.Yushiwen,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/MrYushiwen/article/details/111736821
- 点赞
- 收藏
- 关注作者
评论(0)