AOP
aop:指在程序运行期间动态的将某段代码切入到指定方法位置进行运行的编程方式。【动态代理】
案例:有个除法方法,定义一个日志类动态记录方法的执行情况。
实现步骤:
1、导入aop模块
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、定义一个业务逻辑类:
public class MathCalculator {
private int div(int i ,int j){
System.out.println("MathCalculator...div执行了");
return i/j;
}
}
3、定义一个日志切面类,切面类里面的方法需要动态的感知div运行情况,并打印日志信息。
public class Log {
public void logStart(){
System.out.println("除法运行。。。参数列表是:{}");
}
public void logEnd(){
System.out.println("除法结束");
}
public void logReturn(){
System.out.println("除法正常返回。。。运行结果是:{}");
}
public void logException(){
System.out.println("除法异常。。。异常信息是:{}");
}
}
通知方法:
- 前置通知(@Before):在目标方法执行之前
- 后置通知(@After):在目标方法执行之后
- 返回通知(@AfterReturning):在目标方法正常返回之后执行
- 异常通知(@AfterThrowing):在目标方法执行出现异常之后执行
- 环绕通知(@Around):动态代理,手动推进目标方法运行。(JoinPoint.procced)
4、给切面类的目标方法标注何时何地地运行(通知注解)
public class Log {
//切入点表达式
@Pointcut("execution(* com.wjh.aop.MathCalculator.*(..))")
public void pointCut(){};
@Before(value = "pointCut()")
public void logStart(){
System.out.println("除法运行。。。参数列表是:{}");
}
@After(value = "pointCut()")
public void logEnd(){
System.out.println("除法结束");
}
@AfterReturning(value = "pointCut()")
public void logReturn(){
System.out.println("除法正常返回。。。运行结果是:{}");
}
@AfterThrowing(value = "pointCut()")
public void logException(){
System.out.println("除法异常。。。异常信息是:{}");
}
5、将切面类和业务逻辑类都加入到容器中
主配置类:
@Configuration
public class MainConfigOfAop {
@Bean
public MathCalculator mathCalculator(){
return new MathCalculator();
}
@Bean
public Log log(){
return new Log();
}
}
6、必须告诉spring哪个类是切面类(给切面类加上注解:@Aspect)
//告诉spring这是一个切面类
@Aspect
public class Log {
7、给配置类加上@EnableAspectJAutoProxy注解,开启基于注解版的aop模式
@Configuration
//开启注解版aop
@EnableAspectJAutoProxy
public class MainConfigOfAop {
测试:
@Test
public void test1(){
ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
MathCalculator calculator = ac.getBean(MathCalculator.class);
calculator.div(1,1);
}
测试结果:
除法运行。。。参数列表是:{}
MathCalculator...div执行了
除法正常返回。。。运行结果是:{}
除法结束
如果想要打印方法名、参数、结果和异常信息:
//告诉spring这是一个切面类
@Aspect
public class Log {
//切入点表达式
@Pointcut("execution(* com.wjh.aop.MathCalculator.*(..))")
public void pointCut(){};
@Before(value = "pointCut()")
public void logStart(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(""+joinPoint.getSignature().getName()+"除法运行。。。参数列表是:{"+ Arrays.asList(args) +"}");
}
@After(value = "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+"}");
}
@AfterThrowing(value = "pointCut()",throwing = "exception")
public void logException(JoinPoint joinPoint,Exception exception){
System.out.println(""+joinPoint.getSignature().getName()+"除法异常。。。异常信息是:{"+exception+"}");
}
}
参数结果:
div除法运行。。。参数列表是:{[1, 1]}
MathCalculator...div执行了
div除法正常返回。。。运行结果是:{1}
div除法结束
出现异常测试:
@Test
public void test1(){
ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
MathCalculator calculator = ac.getBean(MathCalculator.class);
calculator.div(1,0);
}
测试结果:
div除法运行。。。参数列表是:{[1, 0]}
MathCalculator...div执行了
div除法异常。。。异常信息是:{java.lang.ArithmeticException: / by zero}
div除法结束