首先,从一个简单的案例走起
切面
@Aspectpublic class LogAspects { //抽取公共的切入点表达式 //1、本类引用 //2、其他的切面引用 @Pointcut("execution(public int cn.spectrumrpc.aop.MathCalculator.*(..))") public void pointCut(){}; //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入) @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一定要出现在参数表的第一位 @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+"}"); }}
public class MathCalculator { public int div(int i,int j){ System.out.println("MathCalculator...div..."); return i/j; }}
MainConfig
@EnableAspectJAutoProxy@Configurationpublic class MainConfigOfAOP { //业务逻辑类加入容器中 @Bean public MathCalculator calculator(){ return new MathCalculator(); } //切面类加入到容器中 @Bean public LogAspects logAspects(){ return new LogAspects(); }}
测试类
@Testpublic void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class); MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class); mathCalculator.div(1, 0); applicationContext.close();}
主要因为@EnableAspectJAutoProxy
那我们就看看这个类到底干了些什么东西
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy
在这个上面,看到了@Import注解,众所周知,@Import可以为容器导入组件。紧接着,就看看导入的 AspectJAutoProxyRegistrar 为我们干了些什么
首先,这个类继承了@ImportBeanDefinitionRegistrar,可以在registerBeanDefinitions() 中导入组件
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar
所以,紧接着转向了 registerBeanDefinitions() 方法。在其中,有这么一句话
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);// 调用 ->registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);// 调用 ->registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);// 往容器中添加了一个类型为 AnnotationAwareAspectJAutoProxyCreator 名称为 org.springframework.aop.config.internalAutoProxyCreator 的组件
那么,我们紧接着就又转向了 AnnotationAwareAspectJAutoProxyCreator 这个类
首先,看这个类的继承图谱,可以看出,其是一个后置处理器

在IOC容器启动时,将会调用后置处理器相应的方法。其中 如果后置处理器的类型是 InstantiationAwareBeanPostProcessor 将会调用 postProcessBeforeInstantiation 前置方法 。 postProcessAfterInitialization 后置方法。
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null;}public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result;}
在这AbstractAutoProxyCreator 中的这两个方法,其中的处理流程如下:
// 1. 获取 该类的切面方法Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);// 2. 为这个类创建代理,默认是cglib动态代理createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
创建代理完成之后,将代理对象返回
在执行目标类的目标方式时,将会直接代理对象的 DynamicAdvisedInterceptor 的 intercep 方法
// 1. 首先获取这个方法上的切面 this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// 2. new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();// 3. 会依次调用所有处理链的invoke方法,具体的流程如下:
查看这几个切面类的invoke方法即可知道,对应的AOP的前置通知,后置通知,返回通知,异常通知的实现结果,其原理是通过处理链的执行时机来决定的。
