首先,从一个简单的案例走起
切面
@Aspect
public 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
@Configuration
public class MainConfigOfAOP {
//业务逻辑类加入容器中
@Bean
public MathCalculator calculator(){
return new MathCalculator();
}
//切面类加入到容器中
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
测试类
@Test
public 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的前置通知,后置通知,返回通知,异常通知的实现结果,其原理是通过处理链的执行时机来决定的。