一、动态代理
在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式
- 导入aop依赖(spring-aspects)
- 业务逻辑组件和切面类生成的实例对象都必须是注册在ioc容器中的(自己创建的对象是不会执行切面方法的);在定义的切面类上标注@Aspect、配置类上标注@EnableAspectJAutoProxy开启基于注解的aop模式(等同于xml配置<aop:aspectj-autoproxy></aop:aspectj-autoproxy>)
- 在切面类上的每一个(通知)方法上标注通知注解,并且在通知注解上定义切入点表达式(告诉Spring在哪些类、方法以及方法运行前、后执行通知方法)
- 切入点表达式:程序执行到哪些类哪些方法时要进行切入;通过表达式进行定义
- 运行时机:程序执行方法的时机;通过通知注解进行标注
代码实现
定义日志切面类(LogAspects):在程序运行到某个阶段的时候能够通过切面类里的方法介入进去给切面类的目标方法标注何时何地运行(通知注解)
- 前置通知(@Before):在目标方法运行之前执行
- 后置通知(@After):在目标方法运行结束之后运行(无论方法正常结束还是异常结束)
- 返回通知(@AfterReturning):在目标方法正常返回之后运行
- 异常通知(@AfterThrowing):在目标方法出现异常以后运行
- 环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
/** * @Aspect: 告诉Spring当前类是一个切面类 */ @Aspect public class LogAspects { //抽取公共的切入点表达式 @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))") public void pointCut(){}; //本类引用(切入点表达式) @Before("public int com.atguigu.aop.MathCalculator.*(..)")
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
}
//其他的切面引用
@After("com.atguigu.aop.LogAspects.pointCut()") public void logEnd(JoinPoint joinPoint){ System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After"); } //JoinPoint一定要出现在参数表的第一位 @AfterReturning(value="pointCut()",returning="result") public void logReturn(JoinPoint joinPoint,Object result){ System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}"); } @AfterThrowing(value="pointCut()",throwing="exception") public void logException(JoinPoint joinPoint,Exception exception){ System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}"); }
AOP原理
【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】
第一步:@EnableAspectJAutoProxy:这步的作用就是在容器中添加一个AnnotationAwareAspectJAutoProxyCreator的bean组件
标注@EnableAspectJAutoProxy后 -》 @Import(AspectJAutoProxyRegistrar.class),它实现了ImportBeanDefinitionRegistrar接口,registerBeanDefinitions()作用就是给容器中添加一个BeanDefinition
registerBeanDefinitions()调用其他方法判断BeanDefinitionRegistry是否有org.springframework.aop.config.internalAutoProxyCreator的beanName,如果没有则通过传入的AnnotationAwareAspectJAutoProxyCreator.class构建一个RootBeanDefinition对象,beanName就是org.springframework.aop.config.internalAutoProxyCreator
第二步:AnnotationAwareAspectJAutoProxyCreator.class
AnnotationAwareAspectJAutoProxyCreator -》 AnnotationAwareAspectJAutoProxyCreator -》 AspectJAwareAdvisorAutoProxyCreator -》 AbstractAdvisorAutoProxyCreator -》 AbstractAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(一个是后置处理器,一个是自动装配BeanFactory)
AbstractAutoProxyCreator有setBeanFactory(),也有beanPostProcessor的后置处理器的逻辑
AbstractAdvisorAutoProxyCreator重写了setBeanFactory()并且该方法中还调用一个initBeanFactory(),没有重写父类beanPostProcessor的方法
AnnotationAwareAspectJAutoProxyCreator重写了initBeanFactory()