1. 程式人生 > >Spring原始碼分析:AOP分析(三)

Spring原始碼分析:AOP分析(三)

個人扯淡部落格:http://blog.ztgreat.cn

前言

在上篇部落格中,分析了Spring Aop的Advice的實現過程,其中Spring對Advice 使用了介面卡模式,將Advice包裝成了Interceptor,在最後,我們通過Spring提供的介面,實現了PointCut,Advice ,Advisor,至此更加的明白了三者的關係。

在前面的配置中,對於每一個需要被代理的bean,我們都是通過手動配置Advisor,很顯然這是最原始的方式,當然這個從分析的角度出發也是最好分析的,今天我們稍微在那個高階一點,通過相關的配置,指定一些規則,讓Spring 自動的給我們代理需要被代理的bean,這樣就不再需要我們一個一個的配置了。

除錯程式碼

最好的分析方式,當然還是跟著原始碼來看看咯,當然個人覺得在什麼都不知曉的情況下,最好還是不要著眼於具體的每一行程式碼,一行一行的debug,這樣可能會被繞暈,我個人都是反覆先看幾篇,瞭解簡單流程後,對於比較混亂的地方,進行debug,然後再繼續看,最後在進行一次debug,測試,驗證。

說遠了,回到正題,對於除錯程式碼,我們還是延用前面最簡單的程式碼,這裡就重複貼出來了,在Spring原始碼分析:AOP分析(一) 中可以找到,程式碼也很簡單(userServicebeforeAdvice

XML配置

採用xml配置的主要原因,在於好分析。

<bean id="userService" class="com.study.spring.aop.UserServiceImpl"/>

<!--advice-->
<bean id="beforeAdvice" class="com.study.spring.aop.BeforeAdvice" />

<!--定義 advisor-->
<bean id="userServiceAdivsor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
   <property name="advice" ref="beforeAdvice"/>
   <property name="mappedName" value="add"/>
</bean>

<!--定義DefaultAdvisorAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

簡要說明

前4行配置,這個就是簡單的配置我們需要被代理的bean,已經advice(增強)

對於這裡的advisor,採用的是Spring的NameMatchMethodPointcutAdvisor,通過名字我們可以知道,這個是通過名稱來匹配的,當然還有其他的匹配方式,比如RegexpMethodPointcutAdvisor 正則匹配,這個匹配規則就要豐富的很多,為了簡單,當然我們還是採用NameMatchMethodPointcutAdvisor了。

在NameMatchMethodPointcutAdvisor 中,我們指定advice,以及需要被增強的方法(可以多個)。

最後我們在配置一個bean->DefaultAdvisorAutoProxyCreator,這個bean 會自動的根據dvisor建立代理,今天的主角就是它啦。

執行結果

對於userService,如果呼叫add 方法,那麼就會執行的我們增強邏輯(即beforeAdvice),呼叫其它方法,則不會增強,好了,現在該我們的主角登場了。

DefaultAdvisorAutoProxyCreator

繼承體系

注:下圖的繼承關係,刪除了部分分支

20181123111635

我們可以發現,DefaultAdvisorAutoProxyCreator 是一個 BeanPostProcessor,既然是BeanPostProcessor 那這個就好辦了,前面我們已經分析IOC的流程了,在refresh中 會註冊BeanPostProcessor 。

回顧IOC refresh

AbstractApplicationContext -> refresh:

@Override
public void refresh() throws BeansException, IllegalStateException {
   // 同步操作
   synchronized (this.startupShutdownMonitor) {

      // 準備工作,記錄下容器的啟動時間、標記"已啟動"狀態
      prepareRefresh();

      // 這步在前面我們分析過,這步主要將配置檔案就會解析成一個個 Bean 定義,註冊到 BeanFactory 中,
      // 但是此時 Bean 還沒有初始化,只是配置資訊都提取出來了,
      //這步中有 customizeBeanFactory 方法,具體在後面介紹
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 設定 BeanFactory 的類載入器,新增幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
      //這個後面會具體介紹
      prepareBeanFactory(beanFactory);

      try {
         // 如果 Bean 實現了BeanFactoryPostProcessor介面,
         // 那麼在容器初始化以後,Spring 會負責呼叫裡面的 postProcessBeanFactory 方法。

         // 這裡是提供給子類的擴充套件點,到這裡的時候,所有的 Bean 都載入、註冊完成了,但是都還沒有初始化
         // 具體的子類可以在這步的時候新增一些特殊的 BeanFactoryPostProcessor 的實現類或做點什麼事
         postProcessBeanFactory(beanFactory);
         // 呼叫 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);

         // 註冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別
         // 此介面兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 兩個方法分別在 Bean 初始化之前和初始化之後得到執行。
         registerBeanPostProcessors(beanFactory);

         // 初始化當前 ApplicationContext 的 MessageSource,不是重點,忽略
         initMessageSource();

         // 初始化當前 ApplicationContext 的事件廣播器,忽略
         initApplicationEventMulticaster();

         // 模板方法
         // 具體的子類可以在這裡做一些特殊操作
         onRefresh();

         // 註冊事件監聽器,監聽器需要實現 ApplicationListener 介面,忽略
         registerListeners();

         // 初始化所有的 singleton beans
         //(lazy-init 的除外)
         finishBeanFactoryInitialization(beanFactory);

         // 最後,廣播事件,ApplicationContext 初始化完成
         finishRefresh();
      }
     //...省略後續程式碼
   }
}

在註冊BeanPostProcessor 的時候,肯定是會例項化bean的,那麼BeanPostProcessor的介面在什麼時候執行呢?

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

回顧IOC 初始化bean

Spring原始碼分析:IOC容器初始化(二) 中我們分析過,為了方便,這裡再貼下程式碼:

AbstractAutowireCapableBeanFactory ->initializeBean:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
		    // 如果 bean 實現了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 介面,回撥
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
		    // 處理 bean 中定義的 init-method,
            // 或者如果 bean 實現了 InitializingBean 介面,呼叫 afterPropertiesSet() 方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
		    // BeanPostProcessor 的 postProcessAfterInitialization 回撥
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
}

可想而知,Spring AOP 會在 IOC 容器建立 bean 例項(這裡特指 userService)的最後對 bean 進行處理(BeanPostProcessor 呼叫)。其實就是在這一步進行代理增強。

AbstractAutoProxyCreator

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

postProcessAfterInitialization

/**
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@Override
public Object postProcessAfterInitialization(@Nullable 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方法:

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
   // 對於本文的例子,"userService",會得到 一個 NameMatchMethodPointcutAdvisor
   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。

拿到interceptor後,就可以建立代理物件了。

createProxy

我們繼續往下看 createProxy 方法:

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);

   //我們介紹過,如果希望使用 CGLIB 來代理介面,可以配置
   // proxyTargetClass="true",這樣不管有沒有介面,都使用 CGLIB 來生成代理:

   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         // 1. 有介面的,呼叫:proxyFactory.addInterface(ifc);
         // 2. 沒有介面的,呼叫:proxyFactory.setProxyTargetClass(true);
         // 兩者在具體代理實現上策略不同(jdk proxy;cglib proxy)
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }

   // 這個方法會返回匹配了當前 bean 的 advisors 陣列
   // 對於本文的例子,"userService"到這邊的時候會返回 NameMatchMethodPointcutAdvisor
   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);
   }
   //通過 proxyFactory 獲取代理
   return proxyFactory.getProxy(getProxyClassLoader());
}

我們看到,這個方法主要是在內部建立了一個 ProxyFactory 的例項,通過這個例項來建立代理: getProxy(classLoader)

看一下 proxyFactory.getProxy(…)方法:

public Object getProxy(@Nullable ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

這個方法很簡單,建立AOP代理(預設工廠是 DefaultAopProxyFactory),然後建立代理物件,到這裡就和我們在

Spring原始碼分析:AOP分析(一),中分析的內容接上了,後續的建立代理過程在前面已經分析了,這裡就不在繼續了。

至此,關於DefaultAdvisorAutoProxyCreator的部分我們就分析完了。

總結

在本文,我們通過DefaultAdvisorAutoProxyCreator 自動建立bean代理,隨後通過DefaultAdvisorAutoProxyCreator 的繼承關係,我們知道了DefaultAdvisorAutoProxyCreator 是一個 BeanPostProcessor,接著我們簡單的回顧了IOC中關於BeanPostProcessor 的註冊以及在建立bean後執行 BeanPostProcessor 回撥,最終我們知道在 BeanPostProcessor 的回撥方法中,建立代理bean,具體的邏輯在DefaultAdvisorAutoProxyCreator 的父類 AbstractAutoProxyCreator中,其主要邏輯便是獲取該bean的interceptor,然後建立AOPFactory來建立代理,而AOPFactory 預設是 DefaultAopProxyFactory,在建立代理過程中,會根據配置或者類的資訊,選擇採用cglib 代理還是jdk代理,這部分內容,在AOP 分析(一)中我們已經分析過了,至此,關於AOP的分析基本可以告一段落了,整個過程,並沒有徹頭徹尾的分析Spring AOP的實現。

Spring原始碼分析:AOP分析(一) 中我們分析了jdk代理和cglib代理的實現原理,同時我們從ProxyFactoryBean 入手,知道了,Spring 建立代理的流程。

Spring原始碼分析:AOP分析之Advice 中,分析了Spring如何把advice(增強)應用到代理物件上的。

在本文,知道如何通過Spring 自動的為我們需要的代理的物件,建立代理,並指定過濾規則。

當然Spring AOP 中還有很多 高階的用法,但是目前這些對我們理解AOP應該足夠了,如果有需要,再進行深入瞭解分析。