關於spirng aop源碼的一點小理解

一、攔截器順序的理解

攔截器總結:
    總結執行順序:
    preHandle按攔截器定義順序調用
    postHandler按攔截器定義逆序調用
    afterCompletion按攔截器定義逆序調用
    postHandler在攔截器鏈內全部攔截器返成功調用
    afterCompletion只有preHandle返回true才調用複製代碼

二、applicationContext裏面有那些東西

在applicationContext中存在一個beanFactoryjava


進去beanFactory能夠看到beanPostProcessorsweb


進去beanPostProcessors能夠看到AnnotationAwareAspectJAutoProxyCreator
spring


進去AnnotationAwareAspectJAutoProxyCreator能夠看到beanFactory和proxyType和adviseBeans
api


進去beanFactory的singletonObjects能夠看到mathTest代理類,代開一個攔截器,能夠看到裏面全部咱們後面源碼分析的一些參數。好比active=true,targetSource,advisors等
springboot


三、@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裏面代碼bash

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定義信息。app

接下來看看AnnotationAwareAspectJAutoProxyCreatoride

先看看繼承關係

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複製代碼

四、案例

切面

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);
    }
}複製代碼

五、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源碼分析

再看看執行的方法post

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); } }複製代碼

裏面有三個地方值得關注

一、this.currentInterceptorIndex=-1

二、Object interceptorOrInterceptionAdvice =

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

複製代碼

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

下面的圖片爲執行的過程圖。

相關文章
相關標籤/搜索