系列篇幅
- 1. Spring - IOC - 注册组件
- 2. spring - IOC - 依赖注入
- 3. Spring - IOC - 组件扫描规则
- 4. Spring - IOC - 组件的作用域、懒加载、条件判断
- 5. Spring - IOC - 组件的生命周期
- 6. Spring - AOP - 基本使用
前言
本文来整理一下AOP相关知识,这里不直接介绍理论了,我们看下日常工作中如何使用
Filter、Interceptor、ControllerAdvice、AOP的关系
流程说明
- 加入依赖 spring-aspects
- 将业务逻辑组件和切面类都加入到容器中,并将切面类加入注解
@Aspect
- 在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行
切入点表达式
- 开启基于注解的aop模式
@EnableAspectJAutoProxy
通知方法 | 说明 |
---|---|
前置通知(@Before) | 在目标方法运行之前运行 |
后置通知(@After) | 在目标方法正常结束/异常结束之后运行 |
返回通知(@AfterReturning) | 在目标方法正常返回之后运行 |
异常通知(@AfterThrowing) | 在目标方法出现异常之后运行 |
环绕通知(@Around) | 动态代理,手动推进目标方法运行 joinPoint.procced()
|
引入依赖
lombok 推荐: [Lombok 的使用](…/…/Java/编程技巧/Lombok 的使用.md)
<!-- lombok 个人习惯非必须 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<!-- aop切面必须导入 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
常用方法说明
JoinPoint参数必须放在第一位
在某个类方法执行前调用
@After("execution(public int com.xm.demo.MathCalculator.*(..))")
public void logEnd(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.printf("方法:%s 结束,切面类:logEnd 方法", methodName);
}
抽离切面公共表达式,方便阅读与封装
@Pointcut("execution(public int com.xm.demo.MathCalculator.*(..))")
public void pointCut() {
}
/**
* 本类的公共切入表达式
*/
@Before("pointCut()")
public void logStart(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.printf("方法:%s 即将运行,参数列表:%s,切面类:logStart 方法",
methodName, Arrays.asList(args));
}
/**
* 其他类的公共切入表达式
*/
@After("com.xm.demo.LogAspects.pointCut()")
public void logEnd(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.printf("方法:%s 结束,切面类:logEnd 方法", methodName);
}
完整例子
定义功能类,等待切面日志
public class MathCalculator {
public int div(int i, int j) {
System.out.printf("方法:MathCalculator.div(%d,%d)\n", i, j);
return i / j;
}
}
定义切面类@Aspect 一定要加,否则无效
@Aspect
public class LogAspects {
/**
* 抽取公共的切入点表达式
*/
@Pointcut("execution(public int com.xm.demo.MathCalculator.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void logStart(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.printf("方法:%s 即将运行,参数列表:%s,切面类:logStart 方法\n",
methodName, Arrays.asList(args));
}
@After("com.xm.demo.LogAspects.pointCut()")
public void logEnd(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.printf("方法:%s 结束,切面类:logEnd 方法\n", methodName);
}
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.printf("方法:%s 正常返回,返回结果:%s,切面类:logReturn方法\n",
methodName, result);
}
@AfterThrowing(value = "pointCut()", throwing = "exception")
public void logException(JoinPoint joinPoint, Exception exception) {
String methodName = joinPoint.getSignature().getName();
System.out.printf("方法:%s 异常,exception:%s,切面类:logException方法\n",
methodName, exception);
}
}
配置类 @EnableAspectJAutoProxy 一定要加,否则无效
@EnableAspectJAutoProxy
@Configuration
public class MainConfig {
/**
* 业务逻辑类加入容器中
*/
@Bean
public MathCalculator mathCalculator(){
return new MathCalculator();
}
/**
* 切面类加入到容器中
*/
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
使用
public class MainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MainConfig.class);
// 不实用ioc容器的话,切面是无效的
MathCalculator calculator = context.getBean(MathCalculator.class);
int div = calculator.div(4, 2);
System.out.printf("result:%d", div);
}
}
正常结果
方法:div 即将运行,参数列表:[4, 2],切面类:logStart 方法
方法:MathCalculator.div(4,2)
方法:div 结束,切面类:logEnd 方法
方法:div 正常返回,返回结果:2,切面类:logReturn方法
result:2
失败结果
方法:div 即将运行,参数列表:[1, 0],切面类:logStart 方法
方法:MathCalculator.div(1,0)
方法:div 结束,切面类:logEnd 方法
方法:div 异常,exception:java.lang.ArithmeticException: / by zero,切面类:logException方法
全栈-民
发布了182 篇原创文章 · 获赞 33 · 访问量 25万+
私信
关注