Spring AOP 原始碼解析

JavaDoop發表於2018-10-24

之前寫過 IOC 的原始碼分析,那篇文章真的有點長,看完需要點耐心。很多讀者希望能寫一寫 Spring AOP 的原始碼分析文章,這樣讀者看完 IOC + AOP 也就對 Spring 會有比較深的理解了。今天終於成文了,可能很多讀者早就不再等待了,不過主要為了後來者吧。

本文不會像 IOC 原始碼分析那篇文章一樣,很具體地分析每一行 Spring AOP 的原始碼,目標讀者是已經知道 Spring IOC 原始碼是怎麼回事的讀者,因為 Spring AOP 終歸是依賴於 IOC 容器來管理的。

Spring AOP 的原始碼並不簡單,因為它多,所以閱讀原始碼最好就是找到一個分支,追蹤下去。本文定位為走馬觀花,看個大概,不具體到每一個細節。

前言

這一節,我們先來"猜猜" Spring 是怎麼實現 AOP 的。

在 Spring 的容器中,我們面向的物件是一個個的 bean 例項,bean 是什麼?我們可以簡單理解為是 BeanDefinition 的例項,Spring 會根據 BeanDefinition 中的資訊為我們生產合適的 bean 例項出來。

當我們需要使用 bean 的時候,通過 IOC 容器的 getBean(…) 方法從容器中獲取 bean 例項,只不過大部分的場景下,我們都用了依賴注入,所以很少手動呼叫 getBean(...) 方法。

Spring AOP 的原理很簡單,就是動態代理,它和 AspectJ 不一樣,AspectJ 是直接修改掉你的位元組碼。

代理模式很簡單,介面 + 真實實現類 + 代理類,其中 真實實現類 和 代理類 都要實現介面,例項化的時候要使用代理類。所以,Spring AOP 需要做的是生成這麼一個代理類,然後替換掉真實實現類來對外提供服務。

替換的過程怎麼理解呢?在 Spring IOC 容器中非常容易實現,就是在 getBean(…) 的時候返回的實際上是代理類的例項,而這個代理類我們自己沒寫程式碼,它是 Spring 採用 JDK Proxy 或 CGLIB 動態生成的。

getBean(…) 方法用於查詢或例項化容器中的 bean,這也是為什麼 Spring AOP 只能作用於 Spring 容器中的 bean 的原因,對於不是使用 IOC 容器管理的物件,Spring AOP 是無能為力的。

本文使用的除錯程式碼

閱讀原始碼很好用的一個方法就是跑程式碼來除錯,因為自己一行一行地看的話,比較枯燥,而且難免會漏掉一些東西。

下面,我們先準備一些簡單的除錯用的程式碼。

首先先定義兩個 Service 介面:

// OrderService.java
public interface OrderService {

    Order createOrder(String username, String product);

    Order queryOrder(String username);
}
// UserService.java
public interface UserService {

    User createUser(String firstName, String lastName, int age);

    User queryUser();
}
複製程式碼

然後,分別來一個介面實現類:

// OrderServiceImpl.java
public class OrderServiceImpl implements OrderService {

    @Override
    public Order createOrder(String username, String product) {
        Order order = new Order();
        order.setUsername(username);
        order.setProduct(product);
        return order;
    }

    @Override
    public Order queryOrder(String username) {
        Order order = new Order();
        order.setUsername("test");
        order.setProduct("test");
        return order;
    }
}

// UserServiceImpl.java
public class UserServiceImpl implements UserService {

    @Override
    public User createUser(String firstName, String lastName, int age) {
        User user = new User();
        user.setFirstName(firstName);
        user.setLastName(lastName);
        user.setAge(age);
        return user;
    }

    @Override
    public User queryUser() {
        User user = new User();
        user.setFirstName("test");
        user.setLastName("test");
        user.setAge(20);
        return user;
    }
}
複製程式碼

寫兩個 Advice:

public class LogArgsAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("準備執行方法: " + method.getName() + ", 引數列表:" + Arrays.toString(args));
    }
}
複製程式碼
public class LogResultAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target)
            throws Throwable {
        System.out.println(method.getName() + "方法返回:" + returnValue);
    }
}
複製程式碼

配置一下:

2

我們這邊使用了前面文章介紹的配置 Advisor 的方式,我們回顧一下。

每個 advisor 內部持有 advice 例項,advisor 負責匹配,內部的 advice 負責實現攔截處理。配置了各個 advisor 後,配置 DefaultAdvisorAutoProxyCreator 使得所有的 advisor 配置自動生效。

啟動:

public class SpringAopSourceApplication {

   public static void main(String[] args) {

      // 啟動 Spring 的 IOC 容器
      ApplicationContext context = new ClassPathXmlApplicationContext("classpath:DefaultAdvisorAutoProxy.xml");

      UserService userService = context.getBean(UserService.class);
      OrderService orderService = context.getBean(OrderService.class);

      userService.createUser("Tom", "Cruise", 55);
      userService.queryUser();

      orderService.createOrder("Leo", "隨便買點什麼");
      orderService.queryOrder("Leo");
   }
}
複製程式碼

輸出:

準備執行方法: createUser, 引數列表:[Tom, Cruise, 55]
queryUser方法返回:User{firstName='test', lastName='test', age=20, address='null'}
準備執行方法: createOrder, 引數列表:[Leo, 隨便買點什麼]
queryOrder方法返回:Order{username='test', product='test'}
複製程式碼

從輸出結果,我們可以看到:

LogArgsAdvice 作用於 UserService#createUser(…) 和 OrderService#createOrder(…) 兩個方法;

LogResultAdvice 作用於 UserService#queryUser() 和 OrderService#queryOrder(…) 兩個方法;

下面的程式碼分析中,我們將基於這個簡單的例子來介紹。

IOC 容器管理 AOP 例項

本節介紹 Spring AOP 是怎麼作用於 IOC 容器中的 bean 的。

Spring AOP 的使用介紹 那篇文章已經介紹過 DefaultAdvisorAutoProxyCreator 類了,它能實現自動將所有的 advisor 生效。

我們來追蹤下 DefaultAdvisorAutoProxyCreator 類,看看它是怎麼一步步實現的動態代理。然後在這個基礎上,我們再簡單追蹤下 @AspectJ 配置方式下的原始碼實現。

首先,先看下 DefaultAdvisorAutoProxyCreator 的繼承結構:

1

我們可以發現,DefaultAdvisorAutoProxyCreator 最後居然是一個 BeanPostProcessor,在 Spring IOC 原始碼分析的時候說過,BeanPostProcessor 的兩個方法,分別在 init-method 的前後得到執行。

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
複製程式碼

這裡再貼一下 IOC 的原始碼,我們回顧一下:

// AbstractAutowireCapableBeanFactory

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 1. 建立例項
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    ...

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // 2. 裝載屬性
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            // 3. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }
    ...
}
複製程式碼

在上面第 3 步 initializeBean(...) 方法中會呼叫 BeanPostProcessor 中的方法,如下:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   ...
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 1. 執行每一個 BeanPostProcessor 的 postProcessBeforeInitialization 方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      // 呼叫 bean 配置中的 init-method="xxx"
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   ...
   if (mbd == null || !mbd.isSynthetic()) {
      // 我們關注的重點是這裡!!!
      // 2. 執行每一個 BeanPostProcessor 的 postProcessAfterInitialization 方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}
複製程式碼

也就是說,Spring AOP 會在 IOC 容器建立 bean 例項的最後對 bean 進行處理。其實就是在這一步進行代理增強。

我們回過頭來,DefaultAdvisorAutoProxyCreator 的繼承結構中,postProcessAfterInitialization() 方法在其父類 AbstractAutoProxyCreator 這一層被覆寫了:

// AbstractAutoProxyCreator

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}
複製程式碼

繼續往裡看 wrapIfNecessary(...) 方法,這個方法將返回代理類(如果需要的話):

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // 返回匹配當前 bean 的所有的 advisor、advice、interceptor
   // 對於本文的例子,"userServiceImpl""OrderServiceImpl" 這兩個 bean 建立過程中,
   //   到這邊的時候都會返回兩個 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;
}
複製程式碼

這裡有兩個點提一下:

getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null),這個方法將得到所有的可用於攔截當前 bean 的advisor、advice、interceptor。

另一個就是 TargetSource 這個概念,它用於封裝真實實現類的資訊,上面用了 SingletonTargetSource 這個實現類,其實我們這裡也不太需要關心這個,知道有這麼回事就可以了。

我們繼續往下看 createProxy(…) 方法:

// 注意看這個方法的幾個引數,
//   第三個引數攜帶了所有的 advisors
//   第四個引數 targetSource 攜帶了真實實現的資訊
protected Object createProxy(
      Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }

   // 建立 ProxyFactory 例項
   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);

   // 在 schema-based 的配置方式中,我們介紹過,如果希望使用 CGLIB 來代理介面,可以配置
   // proxy-target-class="true",這樣不管有沒有介面,都使用 CGLIB 來生成代理:
   //   <aop:config proxy-target-class="true">......</aop:config>
   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         // 點進去稍微看一下程式碼就知道了,主要就兩句:
         // 1. 有介面的,呼叫一次或多次:proxyFactory.addInterface(ifc);
         // 2. 沒有介面的,呼叫:proxyFactory.setProxyTargetClass(true);
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }

   // 這個方法會返回匹配了當前 bean 的 advisors 陣列
   // 對於本文的例子,"userServiceImpl""OrderServiceImpl" 到這邊的時候都會返回兩個 advisor
   // 注意:如果 specificInterceptors 中有 advice 和 interceptor,它們也會被包裝成 advisor,進去看下原始碼就清楚了
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   for (Advisor advisor : advisors) {
      proxyFactory.addAdvisor(advisor);
   }

   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);

   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }

   return proxyFactory.getProxy(getProxyClassLoader());
}
複製程式碼

我們看到,這個方法主要是在內部建立了一個 ProxyFactory 的例項,然後 set 了一大堆內容,剩下的工作就都是這個 ProxyFactory 例項的了,通過這個例項來建立代理: getProxy(classLoader)

ProxyFactory 詳解

根據上面的原始碼,我們走到了 ProxyFactory 這個類了,我們到這個類來一看究竟。

順著上面的路子,我們首先到 ProxyFactory#getProxy(classLoader) 方法:

public Object getProxy(ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}
複製程式碼

該方法首先通過 createAopProxy() 建立一個 AopProxy 的例項:

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   return getAopProxyFactory().createAopProxy(this);
}
複製程式碼

建立 AopProxy 之前,我們需要一個 AopProxyFactory 例項,然後看 ProxyCreatorSupport 的構造方法:

public ProxyCreatorSupport() {
   this.aopProxyFactory = new DefaultAopProxyFactory();
}
複製程式碼

這樣就將我們導到 DefaultAopProxyFactory 這個類了,我們看它的 createAopProxy(…) 方法:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

   @Override
   public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      // (我也沒用過這個optimize,預設false) || (proxy-target-class=true) || (沒有介面)
      if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
         Class<?> targetClass = config.getTargetClass();
         if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                  "Either an interface or a target is required for proxy creation.");
         }
         // 如果要代理的類本身就是介面,也會用 JDK 動態代理
         // 我也沒用過這個。。。
         if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
         }
         return new ObjenesisCglibAopProxy(config);
      }
      else {
         // 如果有介面,會跑到這個分支
         return new JdkDynamicAopProxy(config);
      }
   }
   // 判斷是否有實現自定義的介面
   private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
      Class<?>[] ifcs = config.getProxiedInterfaces();
      return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
   }

}
複製程式碼

到這裡,我們知道 createAopProxy 方法有可能返回 JdkDynamicAopProxy 例項,也有可能返回 ObjenesisCglibAopProxy 例項,這裡總結一下:

如果被代理的目標類實現了一個或多個自定義的介面,那麼就會使用 JDK 動態代理,如果沒有實現任何介面,會使用 CGLIB 實現代理,如果設定了 proxy-target-class="true",那麼都會使用 CGLIB。

JDK 動態代理基於介面,所以只有介面中的方法會被增強,而 CGLIB 基於類繼承,需要注意就是如果方法使用了 final 修飾,或者是 private 方法,是不能被增強的。

有了 AopProxy 例項以後,我們就回到這個方法了:

public Object getProxy(ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}
複製程式碼

我們分別來看下兩個 AopProxy 實現類的 getProxy(classLoader) 實現。

JdkDynamicAopProxy 類的原始碼比較簡單,總共兩百多行,

@Override
public Object getProxy(ClassLoader classLoader) {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
   }
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
複製程式碼

java.lang.reflect.Proxy.newProxyInstance(…) 方法需要三個引數,第一個是 ClassLoader,第二個引數代表需要實現哪些介面,第三個引數最重要,是 InvocationHandler 例項,我們看到這裡傳了 this,因為 JdkDynamicAopProxy 本身實現了 InvocationHandler 介面。

InvocationHandler 只有一個方法,當生成的代理類對外提供服務的時候,都會導到這個方法中:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
複製程式碼

下面來看看 JdkDynamicAopProxy 對其的實現:

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

   TargetSource targetSource = this.advised.targetSource;
   Class<?> targetClass = null;
   Object target = null;

   try {
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         // The target does not implement the equals(Object) method itself.
         // 代理的 equals 方法
         return equals(args[0]);
      }
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         // The target does not implement the hashCode() method itself.
         // 代理的 hashCode 方法
         return hashCode();
      }
      else if (method.getDeclaringClass() == DecoratingProxy.class) {
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         // 
         return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         // Service invocations on ProxyConfig with the proxy config...
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal;

      // 如果設定了 exposeProxy,那麼將 proxy 放到 ThreadLocal 中
      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }

      // May be null. Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
      target = targetSource.getTarget();
      if (target != null) {
         targetClass = target.getClass();
      }

      // Get the interception chain for this method.
      // 建立一個 chain,包含所有要執行的 advice
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don't, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      if (chain.isEmpty()) {
         // 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.
         // chain 是空的,說明不需要被增強,這種情況很簡單
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         // 執行方法,得到返回值
         invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         // Special case: it returned "this" and the return type of the method
         // is type-compatible. Note that we can't help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
      }
      else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
         throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      }
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}
複製程式碼

上面就三言兩語說了一下,感興趣的讀者自己去深入探索下,不是很難。簡單地說,就是在執行每個方法的時候,判斷下該方法是否需要被一次或多次增強(執行一個或多個 advice)。

說完了 JDK 動態代理 JdkDynamicAopProxy#getProxy(classLoader),我們再來瞄一眼 CGLIB 的代理實現 ObjenesisCglibAopProxy#getProxy(classLoader)。

ObjenesisCglibAopProxy 繼承了 CglibAopProxy,而 CglibAopProxy 繼承了 AopProxy。

ObjenesisCglibAopProxy 使用了 Objenesis 這個庫,和 cglib 一樣,我們不需要在 maven 中進行依賴,因為 spring-core.jar 直接把它的原始碼也搞過來了。

3

通過 CGLIB 生成代理的程式碼量有點大,我們就不進行深入分析了,我們看下大體的骨架。它的 getProxy(classLoader) 方法在父類 CglibAopProxy 類中:

// CglibAopProxy#getProxy(classLoader)

@Override
public Object getProxy(ClassLoader classLoader) {
      ...
      // Configure CGLIB Enhancer...
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      // fixedInterceptorMap only populated at this point, after getCallbacks call above
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // Generate the proxy class and create a proxy instance.
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (CodeGenerationException ex) {
      ...
   }
   catch (IllegalArgumentException ex) {
      ...
   }
   catch (Throwable ex) {
      ...
   }
}
複製程式碼

CGLIB 生成代理的核心類是 Enhancer 類,這裡就不展開說了。

基於註解的 Spring AOP 原始碼分析

上面我們走馬觀花地介紹了使用 DefaultAdvisorAutoProxyCreator 來實現 Spring AOP 的原始碼,這裡,我們也同樣走馬觀花地來看下 @AspectJ 的實現原理。

我們之前說過,開啟 @AspectJ 的兩種方式,一個是 <aop:aspectj-autoproxy/>,一個是 @EnableAspectJAutoProxy,它們的原理是一樣的,都是通過註冊一個 bean 來實現的。

解析 <aop:aspectj-autoproxy/> 需要用到 AopNamespaceHandler:

4

然後到類 AspectJAutoProxyBeanDefinitionParser:

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {

   @Override
   @Nullable
   public BeanDefinition parse(Element element, ParserContext parserContext) {
      AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
      extendBeanDefinition(element, parserContext);
      return null;
   }
   ...
}
複製程式碼

進去 registerAspectJAnnotationAutoProxyCreatorIfNecessary(...) 方法:

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      ParserContext parserContext, Element sourceElement) {

   BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
         parserContext.getRegistry(), parserContext.extractSource(sourceElement));
   useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
   registerComponentIfNecessary(beanDefinition, parserContext);
}
複製程式碼

再進去 AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(...):

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
      @Nullable Object source) {

   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
複製程式碼

最終我們看到,Spring 註冊了一個 AnnotationAwareAspectJAutoProxyCreator 的 bean,beanName 為:"org.springframework.aop.config.internalAutoProxyCreator"。

我們看下 AnnotationAwareAspectJAutoProxyCreator 的繼承結構:

5

和前面介紹的 DefaultAdvisorAutoProxyCreator 一樣,它也是一個 BeanPostProcessor,剩下的我們就不說了,它和它的父類 AspectJAwareAdvisorAutoProxyCreator 都不復雜。

閒聊 InstantiationAwareBeanPostProcessor

為什麼要說這個呢?因為我發現,很多人都以為 Spring AOP 是通過這個介面來作用於 bean 生成代理的。

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

   Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

   boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

   PropertyValues postProcessPropertyValues(
         PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;

}
複製程式碼

它和 BeanPostProcessor 的方法非常相似,而且它還繼承了 BeanPostProcessor。

不仔細看還真的不好區分,下面是 BeanPostProcessor 中的兩個方法:

Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
複製程式碼

發現沒有,InstantiationAwareBeanPostProcessor 是 Instantiation,BeanPostProcessor 是 Initialization,它代表的是 bean 在例項化完成並且屬性注入完成,在執行 init-method 的前後進行作用的。

而 InstantiationAwareBeanPostProcessor 的執行時機要前面一些,大家需要翻下 IOC 的原始碼:

// AbstractAutowireCapableBeanFactory 447行
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
   ...
   try {
      // 讓 InstantiationAwareBeanPostProcessor 在這一步有機會返回代理
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean; 
      }
   }
   // BeanPostProcessor 是在這裡面例項化後才能得到執行
   Object beanInstance = doCreateBean(beanName, mbdToUse, args);
   ...
   return beanInstance;
}
複製程式碼

點進去看 resolveBeforeInstantiation(beanName, mbdToUse) 方法,然後就會導到 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法,對於我們分析的 AOP 來說,該方法的實現在 AbstractAutoProxyCreator 類中:

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    ...
    if (beanName != null) {
      TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
      if (targetSource != null) {
         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;
}
複製程式碼

我們可以看到,這裡也有建立代理的邏輯,以至於很多人會搞錯。確實,這裡是有可能建立代理的,但前提是對於相應的 bean 我們有自定義的 TargetSource 實現,進到 getCustomTargetSource(...) 方法就清楚了,我們需要配置一個 customTargetSourceCreators,它是一個 TargetSourceCreator 陣列。

這裡就不再展開說 TargetSource 了,請參考 Spring Reference 中的 Using TargetSources

小結

本文真的是走馬觀花,和我之前寫的文章有很大的不同,希望讀者不會嫌棄。

本文說細節說得比較少,如果你在看原始碼的時候碰到不懂的,歡迎在評論區留言與大家進行交流。

(全文完)


相關文章