关于spirng aop源码的一点小理解

182 阅读4分钟

1、拦截器顺序的理解

拦截器总结:
    总结执行顺序:
    preHandle按拦截器定义顺序调用
    postHandler按拦截器定义逆序调用
    afterCompletion按拦截器定义逆序调用
    postHandler在拦截器链内所有拦截器返成功调用
    afterCompletion只有preHandle返回true才调用

2、applicationContext里面有那些东西

在applicationContext中存在一个beanFactory


进去beanFactory可以看到beanPostProcessors


进去beanPostProcessors可以看到AnnotationAwareAspectJAutoProxyCreator


进去AnnotationAwareAspectJAutoProxyCreator可以看到beanFactory和proxyType和adviseBeans


进去beanFactory的singletonObjects可以看到mathTest代理类,代开一个拦截器,可以看到里面所有我们后面源码分析的一些参数。比如active=true,targetSource,advisors等


3、@EnableAspectJAutoProxy

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   boolean proxyTargetClass() default false;
   boolean exposeProxy() default false;
}

进入注解EnableAspectJAutoProxy可以发现@Import(AspectJAutoProxyRegistrar.class),注入了一个AspectJAutoProxyRegistrar的组件,我们在看看AspectJAutoProxyRegistrar里面代码

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
      Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
      BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
      if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
         int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
         int requiredPriority = findPriorityForClass(cls);
         if (currentPriority < requiredPriority) {
            apcDefinition.setBeanClassName(cls.getName());
         }
      }
      return null;
   }

   RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
   beanDefinition.setSource(source);
   beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
   beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
   registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
   return beanDefinition;
}

public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
      "org.springframework.aop.config.internalAutoProxyCreator";@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {

   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

从上面的代码可以看出在ioc初始化的时候BeanDefinition中保存了name为org.springframework.aop.config.internalAutoProxyCreator,类为AnnotationAwareAspectJAutoProxyCreator的Bean定义信息。

接下来看看AnnotationAwareAspectJAutoProxyCreator

先看看继承关系

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator;
public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator;
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator ;
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport;
      implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware;
从这里可以看出他的父类实现了SmartInstantiationAwareBeanPostProcessor
, BeanFactoryAware这两个接口,
看看后置处理器做了什么?
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
   Object cacheKey = getCacheKey(beanClass, beanName);

   if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
      if (this.advisedBeans.containsKey(cacheKey)) {
         return null;
      }
      if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
         this.advisedBeans.put(cacheKey, Boolean.FALSE);
         return null;
      }
   }

   // Create proxy here if we have a custom TargetSource.
   // Suppresses unnecessary default instantiation of the target bean:
   // The TargetSource will handle target instances in a custom fashion.
   TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
   if (targetSource != null) {
      if (StringUtils.hasLength(beanName)) {
         this.targetSourcedBeans.add(beanName);
      }
      Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
      Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }

   return null;
}从上面的代码可以看出他将所有的代理类的增强拦截器(before,after等,加上事务管理的TransationInterceptor),目标类等,都会
整理出来保存到代理类中。到这里其实前置条件已经基本完成了。le

4、案例

切面

package com.felix.springbootdemo.aspects;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;

@Aspect
@Slf4j
public class MathAspect {
    @Pointcut("execution(public * com.felix.springbootdemo.test.*.*(..))")
    public void test() {
    }

    @Before("test()")
    public void doBefore(JoinPoint joinPoint) {
        //获取方法名称
        String name = joinPoint.getSignature().getName();
        //获取参数
        List<Object> list = Arrays.asList(joinPoint.getArgs());
        log.info("方法{}前置增强,参数为:{}", name, list);
    }

    @After("test()")
    public void doAfter(JoinPoint joinPoint) {
        //获取方法名称
        String name = joinPoint.getSignature().getName();
        //获取参数
        List<Object> list = Arrays.asList(joinPoint.getArgs());
        log.info("方法{}后置增强,参数为:{}", name, list);
    }

    @AfterReturning(value = "test()", returning = "returning")
    public void doAfterReturning(JoinPoint joinPoint, Object returning) {
        //获取方法名称
        String name = joinPoint.getSignature().getName();
        //获取参数
        List<Object> list = Arrays.asList(joinPoint.getArgs());
        log.info("方法{}返回增强,参数为:{},返回值为:{}", name, list, returning);
    }

    @AfterThrowing(value = "test()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        //获取方法名称
        String name = joinPoint.getSignature().getName();
        //获取参数
        List<Object> list = Arrays.asList(joinPoint.getArgs());
        log.info("方法{}异常增强,参数为:{},异常为:{}", name, list, e.getMessage());
    }
}

配置文件

package com.felix.springbootdemo.config;

import com.felix.springbootdemo.aspects.MathAspect;
import com.felix.springbootdemo.test.MathTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    @Bean
    public MathTest mathTest() {
        return new MathTest();
    }

    @Bean
    public MathAspect mathAspect() {
        return new MathAspect();
    }
}

目标类

package com.felix.springbootdemo.test;

public class MathTest {
    public int div(int x, int y) {
        return x / y;
    }
}


测试类

package com.felix.springbootdemo.config;

import com.felix.springbootdemo.test.MathTest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

@Slf4j
public class Test {
    @org.junit.jupiter.api.Test
    public void test() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
        MathTest bean = applicationContext.getBean(MathTest.class);
        log.info("{}", bean);
        bean.div(1, 1);
    }
}

5、aop拦截器流程

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;
   Object target = null;
   TargetSource targetSource = this.advised.getTargetSource();
   try {
      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      Object retVal;
      // Check whether we only have one InvokerInterceptor: that is,
      // no real advice, but just reflective invocation of the target.
      if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
         // We can skip creating a MethodInvocation: just invoke the target directly.
         // Note that the final invoker must be an InvokerInterceptor, so we know
         // it does nothing but a reflective operation on the target, and no hot
         // swapping or fancy proxying.
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = methodProxy.invoke(target, argsToUse);
      }
      else {
         // We need to create a method invocation...
         retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
      }
      retVal = processReturnType(proxy, target, method, retVal);
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);这个方法是获取拦截器链,其中在获取拦截器的时候,在使用适配器模式将所有的拦截器封装成Advisor

再看看执行的方法

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

@Override
@Nullable
public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

里面有三个地方值得关注

1、this.currentInterceptorIndex=-1

2、Object interceptorOrInterceptionAdvice =

         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

3、return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

下面的图片为执行的过程图。