AOP:【动态代理】 能在程序运行期间动态的将某段代码片段切入到指定的方法指定位置进行运行的编程方式;
1、导入aop模块,Spring AOP:(spring-aspects) 2、定义一个业务逻辑类(MathCalculator),在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、包括方法出现异常等等) 3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里了然后执行 切面类里面的方法就是通知方法: (1)前置通知(@Before):logStart,在目标方法(div)运行之前运行 (2)后置通知(@After):logEnd,在目标方法(div)运行之前运行 (3)返回通知(@AfterReturning):logReturn,在目标方法(div)执行返回(无论是正常返回还是异常返回)之后运行 (4)异常通知(@AfterThrowing):logException,在目标方法(div)出现异常之后运行 (5)环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced()) 4、给切面类的目标方法标注何时何地运行(通知注解) 5、将切面类和业务逻辑类(目标方法所在的类)都加入到容器中; 6、必须要告诉Spring哪一个类是切面类(只要给切面类上加上一个注解:@Aspect) 7、给配置类中加入@EnableAspectJAutoProxy:开启基于注解的aop模式
AOP核心jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
MathCalculator.java
package com.hutu.boot01.aop;
public class MathCalculator {
public int div(int a, int b) {
System.out.println("MathCalculator...div...");
return a / b;
}
}
LogAspects.java
package com.hutu.boot01.aop;
import org.aspectj.lang.annotation.*;
@Aspect
public class LogAspects {
//抽取公共的切入点表达式
//本类引用:pointCut()
//其他的切面类要引用
@Pointcut("execution(public int com.hutu.boot01.aop.MathCalculator.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void logStart() {
System.out.println("除法运行...参数列表是:{}");
}
@After("pointCut()")
public void logEnd() {
System.out.println("除法结束...");
}
@AfterReturning("pointCut()")
public void logReturn() {
System.out.println("除法正常返回...运行结果为:{}");
}
@AfterThrowing("pointCut()")
public void logException() {
System.out.println("除法异常...异常信息为:{}");
}
}
MainConfigOfAOP.java
package com.hutu.boot01.config;
import com.hutu.boot01.aop.LogAspects;
import com.hutu.boot01.aop.MathCalculator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* AOP:【动态代理】
* 能在程序运行期间动态的将某段代码片段切入到指定的方法指定位置进行运行的编程方式;
* <p>
* 1、导入aop模块,Spring AOP:(spring-aspects)
* 2、定义一个业务逻辑类(MathCalculator),在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、包括方法出现异常等等)
* 3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里了然后执行
* 切面类里面的方法就是通知方法:
* (1)前置通知(@Before):logStart,在目标方法(div)运行之前运行
* (2)后置通知(@After):logEnd,在目标方法(div)运行之前运行
* (3)返回通知(@AfterReturning):logReturn,在目标方法(div)执行返回(无论是正常返回还是异常返回)之后运行
* (4)异常通知(@AfterThrowing):logException,在目标方法(div)出现异常之后运行
* (5)环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
* 4、给切面类的目标方法标注何时何地运行(通知注解)
* 5、将切面类和业务逻辑类(目标方法所在的类)都加入到容器中;
* 6、必须要告诉Spring哪一个类是切面类(只要给切面类上加上一个注解:@Aspect)
* 7、给配置类中加入@EnableAspectJAutoProxy:开启基于注解的aop模式
*/
@Configuration
@EnableAspectJAutoProxy
public class MainConfigOfAOP {
@Bean
public MathCalculator mathCalculator() {
return new MathCalculator();
}
@Bean
public LogAspects logAspects() {
return new LogAspects();
}
}
测试
@Test
public void test_aop(){
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
MathCalculator bean = context.getBean(MathCalculator.class);
bean.div(1, 1);
}
结果
除法运行...参数列表是:{}
MathCalculator...div...
除法正常返回...运行结果为:{}
除法结束...
完善: 在切面里面的通知方法里面获取方法名、参数、返回值以及异常等等:
package com.hutu.boot01.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import java.util.Arrays;
@Aspect
public class LogAspects {
//抽取公共的切入点表达式
//本类引用:pointCut()
//其他的切面类要引用
@Pointcut("execution(public int com.hutu.boot01.aop.MathCalculator.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void logStart(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName() + "除法运行...参数列表是:" + Arrays.asList(joinPoint.getArgs()));
}
@After("pointCut()")
public void logEnd(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName() + "除法结束...");
}
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(JoinPoint joinPoint, Object result) {
System.out.println(joinPoint.getSignature().getName() + "除法正常返回...运行结果为:" + result);
}
//JoinPoint这个参数一定要出现在参数列表的第一位
@AfterThrowing(value = "pointCut()", throwing = "exception")
public void logException(JoinPoint joinPoint, Exception exception) {
System.out.println("除法异常...异常信息为:{}");
}
}
结果
div除法运行...参数列表是:[1, 1]
MathCalculator...div...
div除法正常返回...运行结果为:1
div除法结束...
注意:如果我们要写JoinPoint这个参数,那么这个参数一定要写在参数列表的第一位 。
主要把握三步: 一、将业务逻辑组件和切面类都加入到IOC容器中,并且告诉Spring哪一个是切面类(@Aspect) 二、在切面类上的每一个通知方法标注通知注解:告诉Spring何时何地运行(写好切入点表达式) 三、开启基于注解的AOP模式:@EnableAspectJAutoProxy