AOP:【动态代理】

指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;

使用

  1. 导入aop模块;Spring AOP:(spring-aspects)
  2. 定义一个业务逻辑类,在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
  3. 定义一个日志切面类:切面类里面的方法需要动态感知目标方法运行到哪里然后执行;
  • 前置通知 @Before:在目标方法运行之前运行;
  • 后置通知 @After:在目标方法运行结束之后运行(无论方法正常结束还是异常结束);
  • 返回通知@AfterReturning:在目标方法正常返回之后运行;
  • 异常通知 @AfterThrowing:在目标方法出现异常以后运行;
  • 环绕通知 @Around:动态代理,手动推进目标方法运行(joinPoint.procced());
  1. 给切面类的目标方法标注何时何地运行(通知注解);
  2. 将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
  3. 必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect);
  4. 给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】;

1、导入aop模块;

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.16.RELEASE</version>
</dependency>

2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)

public class MathCalculator  {
	public int div(int i,int j){
		System.out.println("MathCalculator div");
		return i/j;
	}
}

3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知 MathCalculator.div 运行到哪里然后执行;

4、给切面类的目标方法标注何时何地运行(通知注解);

/**
 * 切面类
 */
@Aspect //切面类注解
public class LogAspects {

	//抽取公共的切入点表达式
	//1、本类引用
	//2、其他的切面引用
	//@Pointcut(value = "execution(public int com.atguigu.aop.MathCalculator.div(int, int))")
	@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
	public void pointCut(){};

    //前置通知
	//@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
    //joinPoint 方法(切入点),可以拿法方法的参数和返回值等信息
	@Before("pointCut()")
	public void logStart(JoinPoint joinPoint){
        //获取方法参数
		Object[] args = joinPoint.getArgs();
		System.out.println(""+joinPoint.getSignature().getName()+"运行...@Before:参数列表是:{"+ Arrays.asList(args)+"}");
	}

    //后置通知
	@After("pointCut()" )
	public void logEnd(JoinPoint joinPoint){
		System.out.println(""+joinPoint.getSignature().getName()+"结束@After...");
	}

    //返回通知
	//JoinPoint一定要出现在参数表的第一位
    //returning = "result" 方法的返回值,该值会赋值给参数Object result
	@AfterReturning(value = "pointCut()",returning = "result")
	public void logReturn(JoinPoint joinPoint, Object result){
		System.out.println(""+joinPoint.getSignature().getName()+"正常返回... @AfterReturning:运行结果:{"+result+"}");
	}

    //异常通知
    //throwing = "exception" 方法抛出的异常信息,该值会赋值给参数Exception exception
	@AfterThrowing(value="pointCut()",throwing = "exception")
	public void logException(JoinPoint joinPoint, Exception exception){
		System.out.println(""+joinPoint.getSignature().getName()+"异常... @AfterThrowing:异常信息{"+exception+"}");
	}
}

5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;

@EnableAspectJAutoProxy //开启基于注解的aop模式
@Configuration
public class MainConfigOfAOP {

	//业务逻辑加入容器中
	@Bean
	public MathCalculator mathCalculator(){
		return new MathCalculator();
	}

	//切面类加到容器中
	@Bean
	public LogAspects logAspects(){
		return new LogAspects();
	}

}

6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect);

7、给配置类中加 @EnableAspectJAutoProxy【开启基于注解的aop模式】;

测试:

public class IOCTest_AOP {

	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
		MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
		mathCalculator.div(1,1);
	}
}

//打印
div运行...@Before:参数列表是:{[1, 1]}
MathCalculator div
div结束@After...
div正常返回... @AfterReturning:运行结果:{1}

核心三步

1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect);
2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式);
3)、开启基于注解的aop模式;@EnableAspectJAutoProxy