1. 程式人生 > 程式設計 >Spring原始碼之Aop

Spring原始碼之Aop

本文主要介紹Spring的aop:aspectj-autoproxy/標籤,瞭解spring是如何實現掃描註解進行aop的,主要實現是在 AspectJAutoProxyBeanDefinitionParser的parser方法中,另外這裡

還需要了解一下NamespaceHandler,NamespaceHandlerSupport 和 BeanDefinitionParser 的關係,如果不清楚的可以看一下Spring原始碼之ApplicationContext中的解釋。

1 Jdk動態代理和CGLIB代理

​ 在講述aop原始碼之前,需要先了解一下 Jdk 動態代理和 CGLIB 代理的區別和使用。

  • Jdk動態代理

    描述

    Jdk動態代理需要目標類至少實現一個介面,在執行時期生成代理類。

  • CGLIB代理

    描述

    CGLIB代理無需實現介面,通過生成類位元組碼實現代理,比反射稍快,不存在效能問題,但CGLIB會繼承目標物件,需要重寫方法,所以目標物件不能為final類。

2 示例程式碼

2.1 AspetJTest註解

示例是基於註解形式,AspetJTest類為註解類。

package lantao.aop;

import java.lang.annotation.*;

/**
 * @Auther: lantao
 * @Date: 2019-05-09 14:01
 * @Company
: 隨行付支付有限公司 * @maill: [email protected] * @Description: TODO */
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AspetJTest { } 複製程式碼

2.2 Aop配置類

Config為Aop的配置類,Pointcut(切點)配置為AspetJTest註解,則所有使用@AspetJTest註解的方法都會被代理。

package lantao.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import
org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * @Auther: lantao * @Date: 2019-05-09 14:03 * @Company: 隨行付支付有限公司 * @maill: [email protected] * @Description: TODO */ @Aspect @Component public class Config { @Pointcut("@annotation(AspetJTest)") public void serviceAspect() { } @Around("serviceAspect()") public Object Around(ProceedingJoinPoint point) throws Throwable { System.out.println("進入Around方法"); Object proceed = point.proceed(); System.out.println("退出Around方法"); return proceed; } @After("serviceAspect()") public void after(){ System.out.println("進入after方法"); } @Before("serviceAspect()") public void before(){ System.out.println("進入before方法"); } } 複製程式碼

2.3 註解使用類

TestService真正的業務類,例如輸入插入/刪除等,aop代理實現事物。

package lantao.aop;

import org.springframework.stereotype.Service;

/**
 * @Auther: lantao
 * @Date: 2019-05-09 13:59
 * @Company: 隨行付支付有限公司
 * @maill: [email protected]
 * @Description: TODO
 */
@Service
public class TestService {

   @aspetJTest
   public void printInfo() {
      System.out.println("進入了printInfo方法");
   }
}
複製程式碼

2.4 測試類

TestAopMain就是測試類。

package lantao.aop;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;
import java.util.List;

/**
 * @Auther: lantao
 * @Date: 2019-05-09 14:06
 * @Company: 隨行付支付有限公司
 * @maill: [email protected]
 * @Description: TODO
 */
public class TestAopMain {
   public static void main(String[] args) {
      ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-bean-aop.xml");
      TestService bean = classPathXmlApplicationContext.getBean(TestService.class);
      bean.printInfo();
   }
}
複製程式碼

2.5 Aop xml配置類

Xml配置類,在其中有aop:aspectj-autoproxy/標籤,使Aop生效,context:component-scan/開啟註解掃描。

<?xml version="1.0" encoding="UTF-8" ?>
<beans
       xmlns="http://www.springframework.org/schema/beans"
      xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

   <aop:aspectj-autoproxy/>

   <!-- use-default-filters 屬性的預設值為 true,即使用預設的 Filter 進行包掃描,而預設的 Filter 對標有 @Service,@Controller,@Component和@Repository 的註解的類進行掃描 -->
   <context:component-scan base-package="lantao.aop" use-default-filters="false">
      <!-- 只掃描 base-package 的 controller 註解 還有對應的 exclude-filter 標籤 排除 ; use-default-filters="false" 和 include-filter 一起使用 和 exclude-filter一起回拋異常-->
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
   </context:component-scan>

</beans>
複製程式碼

2.6 執行結果

以上程式碼的執行結果

進入Around方法
進入before方法
進入了printInfo方法
退出Around方法
進入after方法
複製程式碼

在執行TestAopMain類中的main方法時,發現getBean方法返回的並不是目標類,而是目標類的代理類

3 XMl標籤解析原始碼講解

3.1 解析Aop配置xml

這裡直接從DefaultBeanDefinitionDocumentReader類的doRegisterBeanDefinitions方法開始講解,因前邊都是xml解析的程式碼,已經在Spring原始碼之XmlBeanFactory中講過了,其中parseBeanDefinitions方法是做標籤解析使用的

DefaultBeanDefinitionDocumentReader . parseBeanDefinitions方法

protected void parseBeanDefinitions(Element root,BeanDefinitionParserDelegate delegate){
   //驗證xml namespace,BeanDefinitionParserDelegate.BEANS_NAMESPACE_URI
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               //對預設標籤處理
               // 這裡只處理 nade namespace 為 http://www.springframework.org/schema/beans 的標籤
               parseDefaultElement(ele,delegate);
            }
            else {
               //對自定義標籤處理 非namespace 為 http://www.springframework.org/schema/beans 的標籤 ,會解析 <context:component-scan base-package="lantao.scan"/> 或者自定義 dubbo
               // 或者 aop
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      //對自定義標籤處理
      delegate.parseCustomElement(root);
   }
}
複製程式碼

這裡直接關注parseCustomElement方法,parseDefaultElement方法處理的是bean標籤。

@Nullable
public BeanDefinition parseCustomElement(Element ele) {
   return parseCustomElement(ele,null);
}

@Nullable
public BeanDefinition parseCustomElement(Element ele,@Nullable BeanDefinition containingBd) {
   // 獲取node的 NameSpaceURI
   String namespaceUri = getNamespaceURI(ele);
   if (namespaceUri == null) {
      return null;
   }
   // 解析自定義標籤 需要在 Meta-inf 檔案加 增加 spring.handlers 檔案 例如:http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
   // 根據指定的 NameSpaceURI 獲取 NamespaceHandler  handler可以參考spring.handlers檔案
   // abstract NamespaceHandlerSupport 實現了 NamespaceHandler 介面,繼而實現了 NamespaceHandler 的兩個個方法(parser,docreate),自定義handler 需要實現 NamespaceHandlerSupport 類
   // 進行 NamespaceHandler 類的 init 方法的 實現, 主要是做註冊 BeanDefinitionParser( registerBeanDefinitionParser ) , 需要自定義解析類 繼承 BeanDefinitionParser 類
   NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
   if (handler == null) {
      error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]",ele);
      return null;
   }
   // 解析操作
   return handler.parse(ele,new ParserContext(this.readerContext,this,containingBd));
}
複製程式碼

這裡主要的工作就是機械NamespaceHandler,這裡通過NamespaceHandlerResolver的resolve方法來解析各種NamespaceHandler,最後進行呼叫解析類的parse方法進行解析,接下來看一下resolve方法

@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
   // 這裡獲取的是所有註冊到 handlerMappings 中的  NamespaceHandler ,
   // 就是 resource/META-INF/spring.handler 中的  key就是namespaceUri ,
   // 這些類都繼承了 NamespaceHandlerSupport 實現了init方法 在init方法中進行 BeanDefinitionParse 的註冊
   Map<String,Object> handlerMappings = getHandlerMappings();
   // 通過 namespaceUri 在 handlerMappings 中獲取對應的處理器或者 className 如果是初始化過的就直接返回,反之進行類初始化工作
   Object handlerOrClassName = handlerMappings.get(namespaceUri);
   if (handlerOrClassName == null) {
      return null;
   }
   else if (handlerOrClassName instanceof NamespaceHandler) {
      return (NamespaceHandler) handlerOrClassName;
   }
   else {
      String className = (String) handlerOrClassName;
      try {
         // 例項化
         Class<?> handlerClass = ClassUtils.forName(className,this.classLoader);
         // 判斷例項化的類的超類或者超級介面 是否是 NamespaceHandler
         if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
            throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                  "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
         }
         NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
         // 註冊 自定義標籤所對應的 解析策略類  解析策略類都繼承了 BeanDefinitionParser ,比如 ComponentScanBeanDefinitionParser
         namespaceHandler.init();
         // 放入快取中
         handlerMappings.put(namespaceUri,namespaceHandler);
         return namespaceHandler;
      }
      catch (ClassNotFoundException ex) {
         throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
               "] for namespace [" + namespaceUri + "]",ex);
      }
      catch (LinkageError err) {
         throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
               className + "] for namespace [" + namespaceUri + "]",err);
      }
   }
}
複製程式碼

resolve方法中一共做了兩件事情

1: 呼叫getHandlerMappings方法解析resources 中的 META-INF/spring.handlers檔案,讀取各種處理類

spring.handlers:
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
複製程式碼

2:進行處理類的例項化操作,然後呼叫處理類init方法,進行解析類(Parser)的註冊,並將例項化的處理類進行快取處理,以備下次使用。

@Override
public void init() {
   // In 2.0 XSD as well as in 2.1 XSD.
   registerBeanDefinitionParser("config",new ConfigBeanDefinitionParser());
   registerBeanDefinitionParser("aspectj-autoproxy",new AspectJAutoProxyBeanDefinitionParser());
   registerBeanDefinitionDecorator("scoped-proxy",new ScopedProxyBeanDefinitionDecorator());
   registerBeanDefinitionParser("spring-configured",new SpringConfiguredBeanDefinitionParser());
}
複製程式碼

resolve方法理解後在回到主方法(parseDefaultElement)中,在例項化和解析操作後,呼叫了處理類的parse方法

return handler.parse(ele,containingBd));
複製程式碼
@Override
@Nullable
public BeanDefinition parse(Element element,ParserContext parserContext) {
   // 在 NamespaceHandlerSupport 中的 parser 集合中獲取 BeanDefinitionParser 的實現類 進行 parser
   BeanDefinitionParser parser = findParserForElement(element,parserContext);
   return (parser != null ? parser.parse(element,parserContext) : null);
}
複製程式碼

findParserForElement方法中通過標籤(aspectj-autoproxy)進行獲取對應的處理類(AspectJAutoProxyBeanDefinitionParser)處理類的註冊在例項化處理類後呼叫init方法已經完成, 接下來看一下 解析類的 parse 方法。

@Override
@Nullable
public BeanDefinition parse(Element element,ParserContext parserContext) {
   // 註冊 AnnotationAwareAspectJAutoProxyCreator
   AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext,element);
  // 擴充套件BeanDefinition 處理 子節點 <aop:include/>
   extendBeanDefinition(element,parserContext);
   return null;
}
複製程式碼

註冊 AnnotationAwareAspectJAutoProxyCreator

在解析**(parse)方法中,首先是註冊了AnnotationAwareAspectJAutoProxyCreator類,這個類是處理註解攔截的代理類,然後又擴充套件了剛剛註冊的AnnotationAwareAspectJAutoProxyCreator**,對xml中aop:aspectj-autoproxy標籤的子節點aop:include/進行了處理。

首先看一下注冊AnnotationAwareAspectJAutoProxyCreator的程式碼

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

   // 註冊 AnnotationAwareAspectJAutoProxyCreator
   BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
         parserContext.getRegistry(),parserContext.extractSource(sourceElement));
   // 處理 proxy-target-class 和  expose-proxy屬性
   useClassProxyingIfNecessary(parserContext.getRegistry(),sourceElement);
   // 註冊 BeanComponentDefinition
   registerComponentIfNecessary(beanDefinition,parserContext);
}
複製程式碼

這裡分為三個步驟

1:通過呼叫AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法進行註冊AnnotationAwareAspectJAutoProxyCreator類。

2:處理aop:aspectj-autoproxy標籤的 proxy-target-classexpose-proxy 屬性。

3:註冊 BeanComponentDefinition ,就是對 AnnotationAwareAspectJAutoProxyCreator 的封裝。具體作用後續補上

先來看第一步註冊的原始碼

@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;
}
複製程式碼

這裡就沒什麼好說的,先判斷一下是否已經註冊,如果已經註冊,則判斷優先順序,如果已註冊優先順序高則直接結束,反之直接建立RootBeanDefinition,通過呼叫DefaultListableBeanFactory的registerBeanDefinition方法進行bean註冊

優先順序判斷程式碼

private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

static {
   // Set up the escalation list...
   APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
   APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
   APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
複製程式碼
private static int findPriorityForClass(@Nullable String className) {
   for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
      Class<?> clazz = APC_PRIORITY_LIST.get(i);
      if (clazz.getName().equals(className)) {
         return i;
      }
   }
   throw new IllegalArgumentException(
         "Class name [" + className + "] is not a known auto-proxy creator class");
}
複製程式碼

註冊說完了繼續看一下對 proxy-target-classexpose-proxy 屬性的處理

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry,@Nullable Element sourceElement) {
   if (sourceElement != null) {
       // 對標籤 proxy-target-class 的處理,使用方法 <aop:config proxy-target-class = "true"> 或 <aop:aspectj-autoproxy proxy-target-class="true"/> 使用
      // 其作用是 強制使用 CGLIB 代理,設定<aop:aspectj-autoproxy proxy-target-class="true"/>  ,或需要使用CGLIB 和 @Aspectj自動代理支援 屬性 <aop:aspectj-autoproxy proxy-target-class="true"/>
      // JDK動態代理需要至少實現一個藉口  CGLIB 不需要實現介面
      boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
      if (proxyTargetClass) {
         AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      }

      // 對 expose-proxy 的處理 其作用是實現 目標物件內部方法呼叫可實現切面的增強
      // 例如 例如 A類中 c方法 呼叫 A類中的 d方法是無法實時切面增強的,需要設定 <aop:aspectj-autoproxy expose-proxy="true"/> 例如 d 方法 有 @Transaction 註解則失效
         boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
      if (exposeProxy) {
         AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
      }
   }
}
複製程式碼

proxy-target-class屬性的作用是強制使用 CGLIB 代理。

expose-proxy屬性的作用是目標物件內部方法呼叫可實現切面的增強,例如Test類中的A,B方法,A呼叫B方法進行資料庫save操作,B方法上有**@Transactional註解,如果A直接呼叫B方法則事物是不起作用的,需要設定expose-proxy=true**,然後使用 ((A)AopContext.currentProxy()).b() 呼叫方式。

註冊整體完成後,看一下主方法的extendBeanDefinition方法,擴充套件BeanDefinition。

private void extendBeanDefinition(Element element,ParserContext parserContext) {
   BeanDefinition beanDef =
      parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
   if (element.hasChildNodes()) {
      addIncludePatterns(element,parserContext,beanDef);
   }
}

private void addIncludePatterns(Element element,ParserContext parserContext,BeanDefinition beanDef) {
   ManagedList<TypedStringValue> includePatterns = new ManagedList<>();
   NodeList childNodes = element.getChildNodes();
   for (int i = 0; i < childNodes.getLength(); i++) {
      Node node = childNodes.item(i);
      if (node instanceof Element) {
         Element includeElement = (Element) node;
         TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
         valueHolder.setSource(parserContext.extractSource(includeElement));
         includePatterns.add(valueHolder);
      }
   }
   if (!includePatterns.isEmpty()) {
      includePatterns.setSource(parserContext.extractSource(element));
      beanDef.getPropertyValues().add("includePatterns",includePatterns);
   }
}
複製程式碼

extendBeanDefinition方法主要是對註冊的AnnotationAwareAspectJAutoProxyCreator就行擴充,如果aop:aspectj-autoproxy標籤還有子標籤,也就是**aop:include/標籤,則會作getPropertyValues.add的操作,這裡的aop:include/標籤如果存在對於解析@Aspect標註的類時有一個match的動作,這裡的內容會在buildAspectJAdvisors**方法中詳細講解。 好了到這裡整個Xml的解析註冊就完成了,接下來看一下具體的實現。

4 SpringBoot 自動配置Aop

5 Aop實現原始碼分析

5.1 術語定義

  1. ClassFilter:類過濾器
  2. Advisor:通知器
  3. targetClass:目標類,或稱被代理的原始類
  4. Advice:通知,或稱攔截器,也就是要增強的程式碼邏輯
  5. MethodMatcher:方法匹配器
  6. Pointcut:切點,由ClassFilterMethodMatcher組成

ClassFilter用於約束一個Advisor(通知器),與指定的targetClass是否匹配,只有匹配的前提下,Advisor才能使用其內部持有的Advice(增強器)targetClass進行增強。

Advisor分兩大類:IntroductionAdvisor(引介通知器)和PointcutAdvisor(切點通知器)。兩類Advisor都是為了增強targetClass,但是作用不一樣。IntroductionAdvisor主要為了給targetClass追加介面(或者說追加更多的方法),這種增強屬於類級別的增強;而PointcutAdvisor主要為了攔截方法,這種增強屬於方法級別的增強。

​ 正是由於兩類Advisor的增強級別不同,而導致了對ClassFilter的使用方式不同。IntroductionAdvisor進行類級別增強,因此只需要直接持有ClassFilter即可;而PointcutAdvisor進行方法級別增強,因此需要同時使用ClassFilterMethodMatcher(方法匹配器)。PointcutAdvisor內部持有一個Pointcut,而Pointcut就是由ClassFilter和MethodMatcher組成的

5.2 AnnotationAwareAspectJAutoProxyCreator類解析

​ 在上面的xml解析aop:aspectj-autoproxy標籤時,一直都在說註冊AnnotationAwareAspectJAutoProxyCreator,其實它是繼承了InstantiationAwareBeanPostProcessor -> BeanPostProcessor的,繼承了 InstantiationAwareBeanPostProcessor 會在例項化之前執行postProcessBeforeInstantiationpostProcessAfterInstantiation方法,但同時它也間接性繼承了BeanPostProcessor,也會在初始化前後執行 postProcessBeforeInstantiationpostProcessAfterInitialization 方法,在createBean方法中有這麼一方法resolveBeforeInstantiation,它就是在例項化之前執行的InstantiationAwareBeanPostProcessor,程式碼如下:

@Override
protected Object createBean(String beanName,RootBeanDefinition mbd,@Nullable Object[] args)
      throws BeanCreationException {

************
   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      // 給BeanPostProcessors一個返回代理而不是目標bean例項的機會
      Object bean = resolveBeforeInstantiation(beanName,mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(),beanName,"BeanPostProcessor before instantiation of bean failed",ex);
   }
**********
}
複製程式碼

5.2.1 postProcessBeforeInstantiation方法解析

​ 建立代理的真正方法就是AbstractAutoProxyCreator.postProcessAfterInitialization方法或 postProcessBeforeInstantiation方法。AbstractAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator的超類。下面先看一下 AbstractAutoProxyCreator.postProcessBeforeInstantiation方法

@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass,String beanName) {
		Object cacheKey = getCacheKey(beanClass,beanName);

    // 判斷beanName是否為空 和 targetSoucedBeans是否包含beanName
		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			// isInfrastructureClass:是否是基礎架構類 就是是否是 aop配置類, 如果是 則不可代理這種
			// shouldSkip 這裡通過呼叫子類 AspectJAwareAdvisorAutoProxyCreator 的 shouldSkip 方法,通過獲取全部的Advisor,來判斷Advisor所屬的bean和入參bean是否是同一個,如果是則不用增強反之可以,
			// 然後會呼叫 super.shouldSkip 排除 bean 名稱 尾部是 .ORIGINA 結尾的bean
			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.

		// 如果有自定義的targetSouce 在這裡就直接建立代理,不需要等到例項化的時候在建立,避免不必要的bean建立例項化
		TargetSource targetSource = getCustomTargetSource(beanClass,beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				// 快取
				this.targetSourcedBeans.add(beanName);
			}
			// 獲取該bean可用的增強器 就是迴圈掃描配置類 , 掃出所有的 before alter around 等
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass,targetSource);
			
			// 根據增強器建立代理
			Object proxy = createProxy(beanClass,specificInterceptors,targetSource);
			// 快取
			this.proxyTypes.put(cacheKey,proxy.getClass());
			return proxy;
		}

		return null;
	}
複製程式碼

postProcessBeforeInstantiation方法主要做了一下幾件事情:

1: 判斷beanName是否為空 和 targetSoucedBeans是否包含beanName

2: 判斷是否是基礎架構類,就是是否是aop配置類, 如果是則不可代理這種,直接返回,還會在判斷 shouldSkip ,這裡通過呼叫子類 AspectJAwareAdvisorAutoProxyCreatorshouldSkip 方法,通過獲取全部的Advisor,來判斷Advisor所屬的bean和入參bean是否是同一個,如果是**(如果是則就是代表該bean是配置類)則不可以增強反之可以,然後會呼叫 super.shouldSkip 排除尾部是 .ORIGINA 結尾的bean**。

3: 獲取自定義的TargetSouce,如果存在就直接建立代理,不需要等到例項化的時候在建立,避免不必要的bean建立例項化。

4: 如果存在自定義的TargetSouce,則獲取該bean可用的增強器 就是迴圈掃描配置類 , 掃出所有的 before alter around ,找到符合該bean的增強器。

5: 根據查詢出來的增強器建立代理並返回。

上述是對存在TargetSource情況的描述,下面我們看一下不存在的情況

5.2.2 postProcessAfterInitialization方法解析

接下來看AbstractAutoProxyCreator類中的postProcessAfterInitialization方法

@Override
	public Object postProcessAfterInitialization(@Nullable Object bean,String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(),beanName);
      //防止 bean 多次被增強。
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
        // 如果需要 則建立代理
				return wrapIfNecessary(bean,cacheKey);
			}
		}
		return bean;
	}
複製程式碼
protected Object wrapIfNecessary(Object bean,String beanName,Object cacheKey) {
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
  // 判斷是否是 基礎配置類或需要跳過的類。如果是則不增強 在下邊的方法中會put
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
  
   // isInfrastructureClass:是否是基礎架構類 就是是否是 aop配置類, 如果是 則不可代理這種
		// shouldSkip 這裡通過呼叫子類 AspectJAwareAdvisorAutoProxyCreator 的 shouldSkip 方法,通過獲取全部的Advisor,來判斷Advisor 所屬的 bean 和入參 bean 是否是同一個,如果是則不用增強反之可以,
		// 然後會呼叫 super.shouldSkip 排除 bean 名稱 尾部是 .ORIGINA 結尾的bean
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(),beanName)) {
      this.advisedBeans.put(cacheKey,Boolean.FALSE);
      return bean;
   }

   // Create proxy if we have advice.
  // 獲取該bean的增強器,如果有
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(),null);
  // 如果增強器不是空 則建立代理
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey,Boolean.TRUE);
     // 建立代理並返回
      Object proxy = createProxy(
            bean.getClass(),new SingletonTargetSource(bean));
     // 增加快取
      this.proxyTypes.put(cacheKey,proxy.getClass());
      return proxy;
   }

   // 增加快取 如果不符合則話put,在上邊的判斷直接返回
   this.advisedBeans.put(cacheKey,Boolean.FALSE);
   return bean;
}
複製程式碼

來解析wrapIfNecessary方法都做了什麼

1: 判斷是否是 基礎配置類或需要跳過的類。

2: 判斷是否是基礎架構類,就是是否是aop配置類, 如果是則不可代理這種,直接返回,還會在判斷 shouldSkip ,這裡通過呼叫子類 AspectJAwareAdvisorAutoProxyCreatorshouldSkip 方法,通過獲取全部的Advisor,來判斷Advisor所屬的bean和入參bean是否是同一個,如果是**(如果是則就是代表該bean是配置類)則不可以增強反之可以,然後會呼叫 super.shouldSkip 排除尾部是 .ORIGINA 結尾的bean**。

3: 獲取該bean符合的增強器。

4: 建立代理並返回。

5: 增加快取。

6: 增加快取 如果存在可用的增強器,則將該bean設定為false,在1中會進行判斷。

獲取增強器
5.2.2.1 findCandidateAdvisors方法獲取全部增強器

wrapIfNecessary中最重要的方法就是getAdvicesAndAdvisorsForBean方法,通過getAdvicesAndAdvisorsForBean方法可以獲取到適合bean增強器,接下來就看看它吧。

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass,@Nullable TargetSource targetSource) {

   // 獲取該bean可以使用的增強器
   List<Advisor> advisors = findEligibleAdvisors(beanClass,beanName);
   if (advisors.isEmpty()) {
      return DO_NOT_PROXY;
   }
   return advisors.toArray();
}
複製程式碼
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass,String beanName) {
   // 獲取所有增強器
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   // 獲取當前bean可以使用的增強器
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors,beanClass,beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}
複製程式碼

findEligibleAdvisors方法中首先獲取了所有的增強器,然後獲取適合bean的增強器,先看一下findCandidateAdvisors方法。

這裡首先執行子類findCandidateAdvisors方法,也就是AnnotationAwareAspectJAutoProxyCreator的。

@Override
	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		// 呼叫父類 findCandidateAdvisors 方法
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
			// 處理註解形式的
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}
複製程式碼

在這裡首先呼叫了父類findCandidateAdvisors方法,也就是處理xml形式的Aop配置,然後執行了buildAspectJAdvisors方法,處理註解形式的aop配置

先看一下父類的findCandidateAdvisors方法

protected List<Advisor> findCandidateAdvisors() {
   Assert.state(this.advisorRetrievalHelper != null,"No BeanFactoryAdvisorRetrievalHelper available");
   return this.advisorRetrievalHelper.findAdvisorBeans();
}
複製程式碼
public List<Advisor> findAdvisorBeans() {
   // Determine list of advisor bean names,if not cached already.
   // 獲取快取的 aop配置類名字,也就是 advisorBeanNames 陣列中的資訊
   String[] advisorNames = this.cachedAdvisorBeanNames;
   if (advisorNames == null) {
      // Do not initialize FactoryBeans here: We need to leave all regular beans
      // uninitialized to let the auto-proxy creator apply to them!
      // 如果 cachedAdvisorBeanNames 不存在則通過BeanFactoryUtils 獲取,條件是 根據型別獲取
      advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory,Advisor.class,true,false);
      this.cachedAdvisorBeanNames = advisorNames;
   }
   // 如果不存在配置類則返回空陣列
   if (advisorNames.length == 0) {
      return new ArrayList<>();
   }

   // 反之理解析
   List<Advisor> advisors = new ArrayList<>();
   for (String name : advisorNames) {
      // 是否是有資格的bean
      if (isEligibleBean(name)) {
         // bean是否正在建立
         if (this.beanFactory.isCurrentlyInCreation(name)) {
            if (logger.isTraceEnabled()) {
               logger.trace("Skipping currently created advisor '" + name + "'");
            }
         }
         else {
            try {
               // 存入到advisors中
               advisors.add(this.beanFactory.getBean(name,Advisor.class));
            }
            catch (BeanCreationException ex) {
               Throwable rootCause = ex.getMostSpecificCause();
               if (rootCause instanceof BeanCurrentlyInCreationException) {
                  BeanCreationException bce = (BeanCreationException) rootCause;
                  String bceBeanName = bce.getBeanName();
                  if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                     if (logger.isTraceEnabled()) {
                        logger.trace("Skipping advisor '" + name +
                              "' with dependency on currently created bean: " + ex.getMessage());
                     }
                     // Ignore: indicates a reference back to the bean we're trying to advise.
                     // We want to find advisors other than the currently created bean itself.
                     continue;
                  }
               }
               throw ex;
            }
         }
      }
   }
   return advisors;
}
複製程式碼

父類方法中主要做了兩件事:

1: 首先先從快取cachedAdvisorBeanNames中獲取,看是否存在Aop的配置類,如果不存在則通過BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory,true,false) 方法獲取Aop的配置類,賦值到快取中。

2:迴圈解析BeanName,通過beanFactory.isCurrentlyInCreation方法判斷beanName是否是正在建立狀態,如果不是則add到advisors中。

接下來看一下buildAspectJAdvisors方法,處理註解形式aop的配置類

public List<Advisor> buildAspectJAdvisors() {
   List<String> aspectNames = this.aspectBeanNames;

   if (aspectNames == null) {
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         if (aspectNames == null) {
            List<Advisor> advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
            // 獲取所有的bean
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory,Object.class,false);
            // 迴圈所有的bean 來獲取增強器
            for (String beanName : beanNames) {
               // 判斷bean是否有資格 預設所有bean都是有資格的 也可以配置 正則表示式 來判斷哪些@aspet bean 是資格的
               // 檢查給定的bean是否有資格進行自動代理。
               // 如果沒有使用<aop:include>元素,則將 includePatterns null 並指定所有bean都是有資格的。如果“includePatterns”為非null,則需要和include中的name機型匹配。
               // 例如 @Aspect標註的類是 config     <aop:include name="config1"/> include的name是 config1 則不匹配, 則@Aspect標註的不生效
               if (!isEligibleBean(beanName)) {
                  continue;
               }
               // We must be careful not to instantiate beans eagerly as in this case they
               // would be cached by the Spring container but would not have been weaved.
               // 獲取bean的type
               Class<?> beanType = this.beanFactory.getType(beanName);
               if (beanType == null) {
                  continue;
               }
               // 判斷是否是 aop配置bean 也就是是否被@Aspect註解標註
               if (this.advisorFactory.isAspect(beanType)) {
                  aspectNames.add(beanName);
                  // 構建成AspectMetadata類
                  AspectMetadata amd = new AspectMetadata(beanType,beanName);

                  // 判斷@Aspect註解中標註的是否為singleton型別,預設的切面類都是singleton型別
                  if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                     MetadataAwareAspectInstanceFactory factory =
                           new BeanFactoryAspectInstanceFactory(this.beanFactory,beanName);
                     // 獲取增強器
                     List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                     // put cache
                     if (this.beanFactory.isSingleton(beanName)) {
                        this.advisorsCache.put(beanName,classAdvisors);
                     } else {
                        this.aspectFactoryCache.put(beanName,factory);
                     }
                     // add advisors
                     advisors.addAll(classAdvisors);
                  } else {
                     // Per target or per this.
                     if (this.beanFactory.isSingleton(beanName)) {
                        throw new IllegalArgumentException("Bean with name '" + beanName +
                              "' is a singleton,but aspect instantiation model is not singleton");
                     }
                     MetadataAwareAspectInstanceFactory factory =
                           new PrototypeAspectInstanceFactory(this.beanFactory,beanName);
                     this.aspectFactoryCache.put(beanName,factory);
                     advisors.addAll(this.advisorFactory.getAdvisors(factory));
                  }
               }
            }
            this.aspectBeanNames = aspectNames;
            return advisors;
         }
      }
   }

   if (aspectNames.isEmpty()) {
      return Collections.emptyList();
   }
   List<Advisor> advisors = new ArrayList<>();
   for (String aspectName : aspectNames) {
      List<Advisor> 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;
}
複製程式碼

buildAspectJAdvisors方法中,主要做了以下事情:

1: 首先獲取所有的bean,通過BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory,false)。

2: 判斷bean是否有資格,預設所有bean都是有資格的,也可以通過配置includePatterns來判斷哪些@aspet bean 是資格的。

配置includePatterns:

使用aop:include/標籤,如果配置aop:include/元素,includePatterns 為非null,則需要和include中的name機型匹配。

如果不配置,則 includePatterns 為 null 並指定所有bean都是有資格的。

例如 @Aspect標註的類是 config <aop:include name="config1"/> include的name是 config1 則不匹配, 則@Aspect標註的不生效。

3: 判斷bean是否是Aop配置類,也就是是否被@Aspect標識。

4: 通過this.advisorFactory.getAdvisors(factory)方法獲取bean的增強器

5: 返回全部增強器, 其中2 3 4 5都是for迴圈中操作。

buildAspectJAdvisors方法中,最重要的就是步驟4,獲取每一個bean的增強器,接著看this.advisorFactory.getAdvisors(factory) 方法:

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
   // 獲取 @Aspect 標註Bean 型別
   Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
   // 獲取 @Aspect 標註Bean 名字
   String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
   // 進行bean驗證
   validate(aspectClass);

   // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
   // so that it will only instantiate once.
   MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
         new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

   List<Advisor> advisors = new ArrayList<>();
   // 獲取除了 標記有 Pointcut 註解 的所有方法
   for (Method method : getAdvisorMethods(aspectClass)) {
      // 獲取每個方法上的 增強器
      Advisor advisor = getAdvisor(method,lazySingletonAspectInstanceFactory,advisors.size(),aspectName);
      if (advisor != null) {
         // add
         advisors.add(advisor);
      }
   }

   // If it's a per target aspect,emit the dummy instantiating aspect.
   if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
      Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
      advisors.add(0,instantiationAdvisor);
   }

   // Find introduction fields.
   for (Field field : aspectClass.getDeclaredFields()) {
      Advisor advisor = getDeclareParentsAdvisor(field);
      if (advisor != null) {
         advisors.add(advisor);
      }
   }

   return advisors;
}
複製程式碼

getAdvisors方法中,通過getAdvisorMethods方法獲取到了除了標記有 Pointcut 註解的其他所有方法,然後通過getAdvisor方法獲取每個方法上的增強器。

getAdvisorMethods方法原始碼:

private List<Method> getAdvisorMethods(Class<?> aspectClass) {
   final List<Method> methods = new ArrayList<>();
   // 獲取除了 標記有 Pointcut 註解 的所有方法
   ReflectionUtils.doWithMethods(aspectClass,method -> {
      // Exclude pointcuts
      if (AnnotationUtils.getAnnotation(method,Pointcut.class) == null) {
         methods.add(method);
      }
   });
   methods.sort(METHOD_COMPARATOR);
   return methods;
}
複製程式碼

getAdvisor方法原始碼:

@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod,MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect,String aspectName) {

   // 驗證
   validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

   // 獲取切點
   AspectJExpressionPointcut expressionPointcut = getPointcut(
         candidateAdviceMethod,aspectInstanceFactory.getAspectMetadata().getAspectClass());
   if (expressionPointcut == null) {
      return null;
   }

   // 例項化 增強器 這裡使用的是PointcutAdvisor通知器,是方法級別的
   return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut,candidateAdviceMethod,aspectInstanceFactory,declarationOrderInAspect,aspectName);
}
複製程式碼

getAdvisor方法中首先做了bean型別的驗證,然後獲取切點,最後開始例項化增強器,這裡例項化增強器使用的是PointcutAdvisor(通知器),實際上InstantiationModelAwarePointcutAdvisorImpl是PointcutAdvisor的一個實現,也就是方法級別的通知器

先看beanType的驗證,validate方法原始碼:

@Override
public void validate(Class<?> aspectClass) throws AopConfigException {
   // If the parent has the annotation and isn't abstract it's an error
  // 是否存在@Aspect註解 和 abstract判斷
   if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null &&
         !Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) {
      throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" +
            aspectClass.getSuperclass().getName() + "]");
   }

   AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
   // 判斷bean型別是否是 Aspect
   if (!ajType.isAspect()) {
      throw new NotAnAtAspectException(aspectClass);
   }
   // 判斷 bean 的 kind 是否是 PERCFLOW PERCFLOWBELOW  這兩種在AOP中是不支援的
   if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {
      throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " +
            "This is not supported in Spring AOP.");
   }
   if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {
      throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " +
            "This is not supported in Spring AOP.");
   }
}
複製程式碼

接下來看獲取增強器切點資訊getPointcut方法原始碼:

@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod,Class<?> candidateAspectClass) {
   // 獲取 判斷增強器型別
   AspectJAnnotation<?> aspectJAnnotation =
         AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
   if (aspectJAnnotation == null) {
      return null;
   }

   // 構建 AspectJExpressionPointcut 類
   AspectJExpressionPointcut ajexp =
         new AspectJExpressionPointcut(candidateAspectClass,new String[0],new Class<?>[0]);
   ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
   if (this.beanFactory != null) {
      ajexp.setBeanFactory(this.beanFactory);
   }
   return ajexp;
}
複製程式碼

通過findAspectJAnnotationOnMethod方法獲取到方法的增強器型別,然後構建AspectJExpressionPointcut類,

最後看一下例項化增強器的程式碼:

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,Method aspectJAdviceMethod,AspectJAdvisorFactory aspectJAdvisorFactory,int declarationOrder,String aspectName) {

   this.declaredPointcut = declaredPointcut;
   this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
   this.methodName = aspectJAdviceMethod.getName();
   this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
   this.aspectJAdviceMethod = aspectJAdviceMethod;
   this.aspectJAdvisorFactory = aspectJAdvisorFactory;
   this.aspectInstanceFactory = aspectInstanceFactory;
   this.declarationOrder = declarationOrder;
   this.aspectName = aspectName;

   if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
      // Static part of the pointcut is a lazy type.
      Pointcut preInstantiationPointcut = Pointcuts.union(
            aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(),this.declaredPointcut);

      // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
      // If it's not a dynamic pointcut,it may be optimized out
      // by the Spring AOP infrastructure after the first evaluation.
      this.pointcut = new PerTargetInstantiationModelPointcut(
            this.declaredPointcut,preInstantiationPointcut,aspectInstanceFactory);
      this.lazy = true;
   }
   else {
      // A singleton aspect.
      this.pointcut = this.declaredPointcut;
      this.lazy = false;
      // 例項化增強器
      this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
   }
}
複製程式碼

在這裡主要關注instantiateAdvice方法,實際上它的作用就是例項化Advice

@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod,AspectJExpressionPointcut expressionPointcut,String aspectName) {

   // 獲取 @Aspect 標註de bean的型別
   Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();

   // 驗證bean
   validate(candidateAspectClass);

   // 獲取方法上的增強器
   AspectJAnnotation<?> aspectJAnnotation =
         AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
   if (aspectJAnnotation == null) {
      return null;
   }

   // If we get here,we know we have an AspectJ method.
   // Check that it's an AspectJ-annotated class
   // 檢查 bean 是否是被 @Aspect標註
   if (!isAspect(candidateAspectClass)) {
      throw new AopConfigException("Advice must be declared inside an aspect type: " +
            "Offending method '" + candidateAdviceMethod + "' in class [" +
            candidateAspectClass.getName() + "]");
   }

   if (logger.isDebugEnabled()) {
      logger.debug("Found AspectJ method: " + candidateAdviceMethod);
   }

   AbstractAspectJAdvice springAdvice;

   // 例項化 增強器 根據不同的型別例項化不通過的增強器
   switch (aspectJAnnotation.getAnnotationType()) {
      case AtPointcut:
         if (logger.isDebugEnabled()) {
            logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
         }
         return null;
      case AtAround:
         springAdvice = new AspectJAroundAdvice(
               candidateAdviceMethod,expressionPointcut,aspectInstanceFactory);
         break;
      case AtBefore:
         springAdvice = new AspectJMethodBeforeAdvice(
               candidateAdviceMethod,aspectInstanceFactory);
         break;
      case AtAfter:
         springAdvice = new AspectJAfterAdvice(
               candidateAdviceMethod,aspectInstanceFactory);
         break;
      case AtAfterReturning:
         springAdvice = new AspectJAfterReturningAdvice(
               candidateAdviceMethod,aspectInstanceFactory);
         AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
         if (StringUtils.hasText(afterReturningAnnotation.returning())) {
            springAdvice.setReturningName(afterReturningAnnotation.returning());
         }
         break;
      case AtAfterThrowing:
         springAdvice = new AspectJAfterThrowingAdvice(
               candidateAdviceMethod,aspectInstanceFactory);
         AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
         if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
            springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
         }
         break;
      default:
         throw new UnsupportedOperationException(
               "Unsupported advice type on method: " + candidateAdviceMethod);
   }

   // Now to configure the advice...
   springAdvice.setAspectName(aspectName);
   springAdvice.setDeclarationOrder(declarationOrder);
   String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
   if (argNames != null) {
      springAdvice.setArgumentNamesFromStringArray(argNames);
   }
   springAdvice.calculateArgumentBindings();

   return springAdvice;
}
複製程式碼

首先這裡還是會首先驗證bean的型別,通過validate方法,接下來獲取method的增強器,依然是通過findAspectJAnnotationOnMethod方法,緊接著判斷bean是否被@Aspect標註,最後通過switch語法例項化增強器 並賦值一些引數配置。

到這裡我們已經獲取到了上下文中所有的可用增強器,到此findCandidateAdvisors方法的程式碼就全部都解析完成了,如果還沒有明白整體流程,可以看一下下方時序圖

5.2.2.2 findAdvisorsThatCanApply匹配適用bean的增強器

接下來根據解析到的增強器進行匹配,查找出適用於需要例項化bean的增強器findAdvisorsThatCanApply方法原始碼:

protected List<Advisor> findAdvisorsThatCanApply(
      List<Advisor> candidateAdvisors,Class<?> beanClass,String beanName) {

   // 設定當前代理物件名稱
   ProxyCreationContext.setCurrentProxiedBeanName(beanName);
   try {
      // 匹配
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors,beanClass);
   }
   finally {
      // 刪除當前代理物件名稱
      ProxyCreationContext.setCurrentProxiedBeanName(null);
   }
}
複製程式碼
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors,Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
			// 在這裡對 IntroductionAdvisor 型別的 Advisor(通知器)做會處理, 因為IntroductionAdvisor 是處理類攔截級別的
			// 僅需要使用classFilter 即可
			if (candidate instanceof IntroductionAdvisor && canApply(candidate,clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			// 對 處理過Advisor 的做 跳過處理
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			// 在這裡對 PointcutAdvisor 型別的 Advisor(通知器) 進行處理,因為 PointcutAdvisor 是方法級別的攔截,需要做 ClassFilter 和 MethodMatcher 判斷
			if (canApply(candidate,clazz,hasIntroductions)) {
				// 將匹配的增強器 add 
				eligibleAdvisors.add(candidate);
			}
		}
		// 返回bean匹配的增強器
		return eligibleAdvisors;
	}
複製程式碼

在上述程式碼中,可以看到,這裡會對Advisor(通知器)做判斷處理,分別是IntroductionAdvisorPointcutAdvisor,他們都分別繼承了Advisor,在本文中是使用PointcutAdvisor的實現類InstantiationModelAwarePointcutAdvisorImpl

區別

IntroductionAdvisor: IntroductionAdvisor主要為了給targetClass追加介面(或者說追加更多的方法),這種增強屬於類級別的增強,所以只需要做ClassFilter判斷。

PointcutAdvisor: PointcutAdvisor主要為了攔截方法,這種增強屬於方法級別的增強,則需要做ClassFilterMethodMatcher的判斷。

在findAdvisorsThatCanApply方法中最重要的就是canApply方法,直接看一下原始碼:

public static boolean canApply(Pointcut pc,Class<?> targetClass,boolean hasIntroductions) {
   Assert.notNull(pc,"Pointcut must not be null");
   // 首先ClassFilter 進行匹配
   if (!pc.getClassFilter().matches(targetClass)) {
      return false;
   }

   MethodMatcher methodMatcher = pc.getMethodMatcher();
   if (methodMatcher == MethodMatcher.TRUE) {
      // No need to iterate the methods if we're matching any method anyway...
      return true;
   }

   IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
   if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
      introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
   }

   Set<Class<?>> classes = new LinkedHashSet<>();
   if (!Proxy.isProxyClass(targetClass)) {
      classes.add(ClassUtils.getUserClass(targetClass));
   }
   classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

   // 迴圈匹配每一個方法
   for (Class<?> clazz : classes) {
      Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
      for (Method method : methods) {
         if (introductionAwareMethodMatcher != null ?
               introductionAwareMethodMatcher.matches(method,targetClass,hasIntroductions) :
               methodMatcher.matches(method,targetClass)) {
            return true;
         }
      }
   }
   return false;
}
複製程式碼

在canApply方法中首先做了ClassFilter的匹配判斷,接下來獲取到Class的全部public方法,遍歷所有方法,進行MethodMatcher的匹配操作,最終將匹配到的Advisor全部返回,到這裡findAdvisorsThatCanApply方法就全部解析完成了。

6 建立代理

5.2 中已經將適配於bean的增強器(Advice)獲取到了,接下來繼續分析主流程wrapIfNecessary方法中的createProxy方法。

protected Object createProxy(Class<?> beanClass,@Nullable String beanName,@Nullable Object[] specificInterceptors,TargetSource targetSource) {

		// 曝光 目標類
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory,beanClass);
		}

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		// 判斷 是否設定了 ProxyTargetClass 是否使用CGLIB
		if (!proxyFactory.isProxyTargetClass()) {
			// 如果沒有設定 ProxyTargetClass 則需要判斷 beanClass 是否應該使用CGLIB  反之使用 JDK動態代理
			if (shouldProxyTargetClass(beanClass,beanName)) {
				proxyFactory.setProxyTargetClass(true);
			} else {
				evaluateProxyInterfaces(beanClass,proxyFactory);
			}
		}

		// 設定bean的增強器和攔截器
		Advisor[] advisors = buildAdvisors(beanName,specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		// 設定目標類
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

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

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

上面的方法其實就是封裝了ProxyFactory,真是建立代理的還是ProxyFactory,接下來看一下getProxy介面。

public Object getProxy(@Nullable ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}
複製程式碼
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   // 判斷使用 CGLIB 還是 JDK動態代理

   // isOptimize : 是否優化處理
   // isProxyTargetClass 是否使用CGLIB代理
   // hasNoUserSuppliedProxyInterfaces 是否實現了介面
   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);
      }
      // 使用CGLIB代理
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      // 使用JDK代理
      return new JdkDynamicAopProxy(config);
   }
}
複製程式碼

接下來就是呼叫getProxy方法進行CGLIB或者JDK代理建立了,然後返回代理類。

CBLIB 和 JDK 代理原始碼後續文章講解。

GItHub : github.com/lantaoGitHu…

參考:my.oschina.net/lixin91/blo…