spring AOP源码阅读分析

理论知识

AOP是面向切面编程(Aspect Oriented Programming)的意思。定义一些切点(pointcut),然后可以在切点织入一些通知(advice),对切点方法进行代理增强,与核心业务逻辑分离开来,以提高系统的可维护性、可扩展性和重用性。

AOP的核心思想是将系统中的功能模块按照不同的关注点进行横切划分,然后通过一种称为“切面”的手段,将这些关注点与主要业务逻辑进行解耦。在Spring AOP中,我们可以通过定义切面、切点和通知三个元素来实现AOP的功能:

  • 切面(Aspect):一组横切关注点的集合,它描述了在何时、何地、何种情况下执行横切关注点。
  • 切点(PointCut):使用表达式语言,匹配目标对象中的连接点(Join Point),从而识别出需要执行横切关注点的地方。
  • 通知(Advisor):它定义了在连接点处执行的代码逻辑,通常包括前置通知(Before Advice)、后置通知(After Advice)、环绕通知(Around Advice)、异常通知(After Throwing Advice)和最终通知(After Returning Advice)等,这些通知组成了切面的核心实现逻辑

在aspectjweaver-1.9.7.jar包里有常用的切面注解。

开启切面代理

需要添加@EnableAspectJAutoProxy注解,会引入AspectJAutoProxyRegistrar类。该类会往BeanDefinitionRegistry里注册一个(org.springframework.aop.config.internalAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator)类型的beanDef。前面bean的实例化过程知道beanDef会被初始化成一个bean。

具体位置AopConfigUtils.registerOrEscalateApcAsRequired方法

private static BeanDefinition registerOrEscalateApcAsRequired(
      Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {//如果这个beanName已注册
      BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
      if (!cls.getName().equals(apcDefinition.getBeanClassName())) {//和当前指定的class不一致
         /**
         查找两个类的优先级
         这里有三个ProxyCreator:
         InfrastructureAdvisorAutoProxyCreator
         AspectJAwareAdvisorAutoProxyCreator
         AnnotationAwareAspectJAutoProxyCreator
         我们通过@EnableAspectJAutoProxy是引入的AnnotationAwareAspectJAutoProxyCreator,这里就是判断如果容器已经指定了creator,如果是其它的两个,这里会被替换掉,也是方法名Escalate升级的意思。Annotation这个优先级最高
         **/
         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;
}

来看下AnnotationAwareAspectJAutoProxyCreator类的结构

spring AOP源码阅读分析_第1张图片

我们发现他实现了BeanPostProcessor接口,是一个bean后置处理器。当一个bean初始化时,会调用beanpostPorocessor的before和after模板方法。其实代理也是在post的这两个方法实现的。具体在AbstractAutoProxyCreator类。

Aspect的解析

后置处理器的AbstractAutoProxyCreator#before方法

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;
      }
      //shouldSkip方法会判断该bean是否需要aop切面
      if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
         this.advisedBeans.put(cacheKey, Boolean.FALSE);
         return null;
      }
   }

   return null;
}

shouldSkip会调用多次,这里面主要时判断当前bean有没有匹配的切面织入点,这里shouldSkip要看AspectJAwareAdvisorAutoProxyCreator子类的实现

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
   //shouldSkip-1 findCandidateAdvisors方法在类AnnotationAwareAspectJAutoProxyCreator
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   //这里找到的advisor都是InstantiationModelAwarePointcutAdvisorImpl类型,for循环不成立
   for (Advisor advisor : candidateAdvisors) {
      if (advisor instanceof AspectJPointcutAdvisor &&
            ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
         return true;
      }
   }
   return super.shouldSkip(beanClass, beanName);
}

shouldSkip-1调用的AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors方法,先获取配置的所有advisor。也就是@Aspect注解标记的类

protected List<Advisor> findCandidateAdvisors() {
   //先从缓存查找
   List<Advisor> advisors = super.findCandidateAdvisors();
   // 不存在构建解析
   if (this.aspectJAdvisorsBuilder != null) {
      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   }
   return advisors;
}

第一次从缓存中无法找到,会走下面的BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors方法去解析advisors

public List buildAspectJAdvisors() {
   List aspectNames = this.aspectBeanNames;

   if (aspectNames == null) {
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         if (aspectNames == null) {
            List advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
            //从这里开始,先拿出所有的bean来
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory, Object.class, true, false);
            for (String beanName : beanNames) {
            //是否有@Aspect注解,调用AnnotationUtils.findAnnotation(clazz, Aspect.class)判断
               if (this.advisorFactory.isAspect(beanType)) {
                  aspectNames.add(beanName);
                  AspectMetadata amd = new AspectMetadata(beanType, beanName);
                  if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                     MetadataAwareAspectInstanceFactory factory =
                           new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                     //buildAspect-2 查找所有的advisor,获取所有的bean方法,过滤掉所有带@Pointcut注解的,然后依次在方法上查找切面的注解
                     List classAdvisors = this.advisorFactory.getAdvisors(factory);
                     if (this.beanFactory.isSingleton(beanName)) {
                     //放入缓存 key是beanName,value是所有的切面advisor方法
                        this.advisorsCache.put(beanName, classAdvisors);
                     }
                     else {
                        this.aspectFactoryCache.put(beanName, factory);
                     }
                     advisors.addAll(classAdvisors);
                  }
                  else {//非单例}
               }
            }
            //解析完一次后,就存起来,下次不用拿出所有的bean进行判断是不是AspectBean了
            this.aspectBeanNames = aspectNames;
            return advisors;
         }
      }
   }
if (aspectNames.isEmpty()) {
			return Collections.emptyList();
		}
		//第二次aspectNames不是空,直接到这里拿出所有的advisor返回
		List advisors = new ArrayList<>();
		for (String aspectName : aspectNames) {
			List cachedAdvisors = this.advisorsCache.get(aspectName);
			if (cachedAdvisors != null) {
				advisors.addAll(cachedAdvisors);
			}
			else {
				MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
				advisors.addAll(this.advisorFactory.getAdvisors(factory));
			}
		}
		return advisors;
}

从上面的advisor解析看到,查找@Aspect是从beanFacotry里查找bean。所以我们的@Aspect也要是一个bean,否则只有@Aspect注解是无效的

buildAspect-2处查找Aspect切面的方法AbstractAspectJAdvisorFactory#findAspectJAnnotationOnMethod

Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
//在方法上查找所有切面注解
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
   for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
      AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
      if (foundAnnotation != null) {
         return foundAnnotation;
      }
   }
   return null;
}
切面方法匹配

上面before方法看完,只是对Aspect进行了解析。没有具体使用,那么继续看after方法。还是从beanpost的after方法

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         //是否需要包装代理
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	    //
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		//不需要代理的类
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
        //又调用一次shouldSkip
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		//after-1 寻找适配这个类的所有advisor
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

after-1处寻找适配的Advisor方法最后会调到findEligibleAdvisors方法

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   List<Advisor> candidateAdvisors = findCandidateAdvisors();//拿出所有的advisor
   //findEligible-1 找出这个类可以使用的advisor
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
   //对通知进行排序,使用的PartialOrder
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

findEligible-1 找匹配的advisor方法

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;
   }
   List<Advisor> eligibleAdvisors = new ArrayList<>();
   for (Advisor candidate : candidateAdvisors) {//这一步是干什么不知道,好像都不匹配
      if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
         eligibleAdvisors.add(candidate);
      }
   }
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();
   for (Advisor candidate : candidateAdvisors) {
      if (candidate instanceof IntroductionAdvisor) {
         // already processed
         continue;
      }
      //会走这里
      if (canApply(candidate, clazz, hasIntroductions)) {
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}

canApply方法

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
   //...
   //拿出所有的类方法与切点规则进行匹配,只要有一个匹配则返回true
   for (Class<?> clazz : classes) {
      Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
      for (Method method : methods) {
         if (introductionAwareMethodMatcher != null ?
         //matches怎么匹配的,看不懂不看了。反正就是拿出来joinPoint切面表达式和方法Signature进行匹配
               introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
               methodMatcher.matches(method, targetClass)) {
            return true;
         }
      }
   }

   return false;
}
代理创建

如果找到切面能匹配当前bean,则该bean需要被代理

创建代理主要在createProxy方法,这里会将所有相关的信息构造成一个ProxyFactory对象,最后调用proxyFactory.getProxy方法获取代理对象。proxyFactory内有一个DefaultAopProxyFactory,其createAopProxy方法用来创建代理对象。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   if (!NativeDetector.inNativeImage() &&
         (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
      Class<?> targetClass = config.getTargetClass();
      //判断目标是否是接口
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {//使用jdk创建动态代理
         return new JdkDynamicAopProxy(config);
      }//使用cglib代理
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

这里可以看到接口类会使用jdk动态代理,其它使用cglib进行创建代理。cglib不太懂,看JdkDynamicAopProxy。这个类实现了InvocationHandler接口。

方法的执行

以jdk代理为例。执行的开始就是handler的invoker方法了。

来看JdkDynamicAopProxy的invoker方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;

   TargetSource targetSource = this.advised.targetSource;
   Object target = null;

   try {
      //...
      Object retVal;
      //这个是根据@EnableAspectJAutoProxy注解的exposeProxy属性判断是否暴露原被代理对象,放到ThreadLocal里,在advisor方法逻辑里就可以获取到被代理对象了。
      if (this.advised.exposeProxy) {
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);
      //invoke-1 从可用advisors中获取拦截器链
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      if (chain.isEmpty()) {
  		//拦截器链为空,直接使用反射调用
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         //invoke-2 根据拦截器链构造MethodInvocation
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         //invoke-3 执行责任链上的方法
         retVal = invocation.proceed();
      }
      return retVal;
   }
   finally {
      //...
      if (setProxyContext) {
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

invoke-1创建拦截器链最后实际处理逻辑在DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice中.前面切点发现的时候说了,某个bean只要有一个方法符合切面匹配。就会被代理。这里实际调用某个方法的时候,还需要再判断一次切面规则是否匹配当前代理类被调用方法。有可能一个类中有的方法符合规则有的不符合规则。

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
      Advised config, Method method, @Nullable Class<?> targetClass) {
   /**intercept-1
    这里获取registry,默认会创建一个DefaultAdvisorAdapterRegistry类型register。
    里面初始化三个adapter:
    	public DefaultAdvisorAdapterRegistry() {
          registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
          registerAdvisorAdapter(new AfterReturningAdviceAdapter());
          registerAdvisorAdapter(new ThrowsAdviceAdapter());
        }
        对应三个切面类型
   */
   AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
   Advisor[] advisors = config.getAdvisors();
   List<Object> interceptorList = new ArrayList<>(advisors.length);
   Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
   Boolean hasIntroductions = null;

   for (Advisor advisor : advisors) {//拿出所有的advisor进行方法匹配
      if (advisor instanceof PointcutAdvisor) {
         // Add it conditionally.
         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
         if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
            MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
            boolean match;
            if (mm instanceof IntroductionAwareMethodMatcher) {
               if (hasIntroductions == null) {
                  hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
               }
               match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
            }
            else {
               match = mm.matches(method, actualClass);
            }
            //匹配
            if (match) {//intercept-2这里根据不同的advisor获取不同类型的拦截器
               MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
               interceptorList.addAll(Arrays.asList(interceptors));
            }
         }
      }
      else if (advisor instanceof IntroductionAdvisor) {
         IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
         if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
         }
      }
      else {
         Interceptor[] interceptors = registry.getInterceptors(advisor);
         interceptorList.addAll(Arrays.asList(interceptors));
      }
   }

   return interceptorList;
}

intercept-2从advisorAdapter获取拦截器

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
   List<MethodInterceptor> interceptors = new ArrayList<>(3);
   Advice advice = advisor.getAdvice();
   if (advice instanceof MethodInterceptor) {
      interceptors.add((MethodInterceptor) advice);
   }
   //这里的adapter对应上面intercept-1初始化的三个切面类型adapter
   for (AdvisorAdapter adapter : this.adapters) {
      if (adapter.supportsAdvice(advice)) {//类型匹配 根据advice获取对应的intecept
         interceptors.add(adapter.getInterceptor(advisor));
      }
   }
   if (interceptors.isEmpty()) {
      throw new UnknownAdviceTypeException(advisor.getAdvice());
   }
   return interceptors.toArray(new MethodInterceptor[0]);
}

invoke-3 proceed方法是执行的关键。这里会递归的调用proceed方法进行所有拦截器invoke

public Object proceed() throws Throwable {
   // 所有拦截器都执行,最后执行切点方法,也就是被代理原方法
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
 	//...
      //proceed 执行拦截器invoke方法
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

这里不同的拦截器内部invoke方法不一样,来看一下:

1-ExposeInvocationInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {
   MethodInvocation oldInvocation = invocation.get();
   invocation.set(mi);
   try {
      return mi.proceed();
   }
   finally {
      invocation.set(oldInvocation);
   }
}

这个没有什么逻辑,就是继续调用下一个。也没注意什么时候生成的,就是threadlocal里执行前后换了下值。

2-MethodBeforeAdviceInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
   return mi.proceed();
}

@Before注解对应拦截器。会先执行before advice方法,然后继续执行下一个拦截器。也就是我们要植入的方法。

before方法的实现会到AspectJMethodBeforeAdvice类里

public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
   invokeAdviceMethod(getJoinPointMatch(), null, null);
}

3-AspectJAfterAdvice

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   finally {
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

@After注解对应的拦截器。最后在执行advice方法。我们看到advice放到的执行放到了finally里,所以@after标记的切面方法即使被代理原方法抛异常也会被执行

4-AspectJAfterThrowingAdvice

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
         invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
   }
}

@AfterThrowing对应拦截器,advisor方法在catch块里,异常时候会执行advisor方法

使用例子

配置开启aop

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
@ComponentScan(basePackages = {"com.cpx.service.aop"})
public class AopConfig {}

切面处理类:

@Component
@Aspect
@Slf4j
public class LogTestAspect {

    @Pointcut("execution(* com.cpx.service.*.*(..))")
    public void point(){};

    @After(value = "point()")
    public void methodAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        log.info("after method execute");
    }

    @AfterThrowing(value = "point()")
    public void afterThrow(JoinPoint joinPoint){
        log.info(" exception happen.............");
    }

    public void test(){
        log.info("hhh");
    }

    @Before(value = "point()")
    public void methodBefore(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        log.info("before method execute");
    }
}

启动测试

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
UserService userService = (UserService) ctx.getBean("userService");
userService.sayHello();
ctx.close();
总结

Spring AOP实现是通过bean后置处理器去实现。在后置处理器方法找到所有的Advisor,即@Aspect注解标注的bean。然后每个被创建的bean都会拿出所有的类方法与解析到的Advisors切点规则进行匹配,只要有一个规则匹配,则该bean会被通过JDK动态代理或cglib方式代理包装返回代理对象。通过代理执行原方法时,会计算出当前方法匹配的所有Advisor规则组成Intecepters依次调用。

你可能感兴趣的:(spring,spring,java,后端)