5-AOP——5-3 針對Bean生成動態(tài)代理

概要

過度

我們前面介紹了對<aop:aspectj-autoproxy />標簽的解析過程,其實整體就做了一件事:創(chuàng)建一個后處理器并注冊。

本文我們主要介紹這個后處理器的工作原理。當然我們關(guān)注的重點是AOP相關(guān)的處理邏輯。

內(nèi)容簡介

結(jié)合我們之前了解的BeanFactory邏輯,了解此后處理器的工作邏輯。

對此后處理器創(chuàng)建AOP的邏輯進行詳細分析,包括:

  1. 找出所有注冊的增強器
  2. 針對要實例化的Bean選擇合適增強器
  3. 利用選出的合適的增強器創(chuàng)建動態(tài)代理

所屬環(huán)節(jié)

針對Bean生成動態(tài)代理

上下環(huán)節(jié)

上文:解析<aop:aspectj-autoproxy />節(jié)點

下文:Spring構(gòu)建的動態(tài)代理對象的工作原理

源碼解析

入口

我們上面講到解析標簽最終會導(dǎo)致AnnotationAwareAspectJAutoProxyCreator的注冊,這個類的繼承關(guān)系如下:

1.png

emmmm,又是一個繼承關(guān)系超級復(fù)雜的類,我們不再像前面學(xué)習(xí)BeanFactory時對每個類的角色、功能一一介紹了,我們把主要注意力集中在調(diào)用上面,這樣能讓我們思路清晰。

這里很容易發(fā)現(xiàn)AbstractAutoProxyCreator繼承了SmartInstantiationAwareBeanPostProcessor。這里應(yīng)該對BeanPostProcessor的主要處理邏輯有實現(xiàn)。

在擴展中,我們對擊中Bean的后處理器做了介紹。根據(jù)我們在擴展中的介紹,我們確認進行AOP動態(tài)代理創(chuàng)建的主要有三個地方:

  • postProcessBeforeInstantiation
  • getEarlyBeanReference
  • postProcessAfterInitialization

其中第一種情況涉及短路,第二、第三種不涉及。而第一種段路但是會繼續(xù)手動調(diào)用postProcessAfterInitialization。所以實際調(diào)用的搭配方案是:

  • 1,3
  • 2,3

我們依次介紹三個調(diào)用方法,最后再整合看。我們先介紹一下基本的數(shù)據(jù)結(jié)構(gòu),方便后續(xù)代碼理解:

基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

// 這個里面存的是通過 TargetSourceCreator 創(chuàng)建的 Bean 實例,不走 Spring 的創(chuàng)建實例、填值、初始化、提前暴露啥的,直接
// 一步走到最后的調(diào)用初始化之后的后處理器
private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// 這個是配合 BeanFactory 進行解決循環(huán)依賴時提供的
// key: 計算得到的 cacheKey
// value: 是完成創(chuàng)建實例后得到的地址。還沒進行填值、初始化啥的
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
// 這個是將已經(jīng)完成代理創(chuàng)建的對象進行緩存
// key: 計算得到的cacheKey
// value: 代理之后得到的 Class
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);
// 已經(jīng)增強的 Bean 的 map ,key 是根據(jù) beanName 生成的。 value 是這個 bean 已經(jīng)增強的原因:
// False 表示經(jīng)過之前的判斷,此 Bean 不需要增強。
// True 表示經(jīng)過之前的判斷,此 Bean 需要增強
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);

四個屬性。

前兩個屬性分別對應(yīng)postProcessBeforeInstantiationgetEarlyBeanReference的實現(xiàn)。

后兩個屬性是做緩存以加快執(zhí)行效率。

postProcessBeforeInstantiation

我們先上代碼:

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

  // TODO targetSourcedBeans 中沒有針對這個 Bean 的緩存??????
  if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
    if (this.advisedBeans.containsKey(cacheKey)) {//TODO 之前對此類 Bean 做過判斷
      return null;
    }
    // 1. AOP配置的基礎(chǔ)類【不需進行AOP】
    // 2. 子類自行定義一個判斷條件,將自己不想進行代理的類摘出去
    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.
  // 這里看一下,我們是不是配置了對應(yīng)的 TargetSourceCreator 來生成此類實例,如果配置了的話就直接走配置生成可用的目標實例
  // 緩存創(chuàng)建的實例,然后在這里創(chuàng)建完成代理,不再走 Spring 的創(chuàng)建實例、屬性填充、初始化啥的操作了
  //
  // 這里主要是提供給使用者一個短路 Spring 基礎(chǔ)流程的機會,方便進行定制
  TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
  if (targetSource != null) {
    // 存起來,表示下次處理 beanName ,直接走  TargetSourceCreator 并創(chuàng)建代理
    if (StringUtils.hasLength(beanName)) {
      this.targetSourcedBeans.add(beanName);
    }
    // 得到我們配置的 Advisor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
    // 根據(jù)我們配置的 Advisor 創(chuàng)建代理對象
    Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
    // TODO 緩存一下我們創(chuàng)建的代理類【這里不清楚有啥用】
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;// 短路
  }

  return null;
}


protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
  // We can't create fancy target sources for directly registered singletons.
  if (this.customTargetSourceCreators != null &&
      this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
    for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
      TargetSource ts = tsc.getTargetSource(beanClass, beanName);
      if (ts != null) {
        // Found a matching TargetSource.
        if (logger.isDebugEnabled()) {
          logger.debug("TargetSourceCreator [" + tsc +
                       "] found custom TargetSource for bean with name '" + beanName + "'");
        }
        return ts;
      }
    }
  }

  // No custom TargetSource found.
  return null;
}

思路如下:

2.png

上面的思路是有點亂的,你只需要明白一點就可以了,這個函數(shù)的職責(zé)是嘗試借助TargetSourceCreator完成實例構(gòu)建,如果可以就可以短路操作,如果不行就走正常創(chuàng)建。這里面的一大堆判斷也是在推斷這個 Bean 是否之前做過這種判斷,有沒有保存好的判斷結(jié)果。

有兩個函數(shù)里封裝了我們的核心操作:

  • getAdvicesAndAdvisorsForBean
  • createProxy

職責(zé)我們大概能猜到,具體的實現(xiàn)思路我們后面統(tǒng)一介紹。

getEarlyBeanReference

先上代碼:

@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
  Object cacheKey = getCacheKey(bean.getClass(), beanName);
  this.earlyProxyReferences.put(cacheKey, bean); // 這里的 Bean 是完成創(chuàng)建實例后得到的地址。還沒進行填值、初始化啥的
  return wrapIfNecessary(bean, beanName, cacheKey);
  //TODO 這里提前進行了包裝,如果是jdk動態(tài)代理,后面在注入時怎么玩????,看看代理之后會不會影響 getter/setter函數(shù)
}

這里思路很簡單,因為實例已經(jīng)存在了,所以我們做緩存,然后根據(jù)情況創(chuàng)建代理即可。其中wrapIfNecessary方法后面詳細介紹。

postProcessAfterInitialization

貼代碼:

/**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     *
     * @see #getAdvicesAndAdvisorsForBean
     */
// 如果要處理的 bean 實例被子類標識為需要代理的,就通過配置的攔截器創(chuàng)建代理
//
// 注意,這里的用詞是攔截器,因為是通過回調(diào)完成的調(diào)用。過濾器 Filter 是和 servlet 容器切合到一起的,
// 是 tomcat 的東西
//
// 這里是將通過 Spring 創(chuàng)建實例、完成添值、初始化完成的對象實例或者前面postProcessBeforeInstantiation()短路
// 得到的完善的實例,在這里將需要進行代理的進行創(chuàng)建代理
//
// 注意,這里需要判斷是否已經(jīng)代理過,別在 postProcessBeforeInstantiation() 創(chuàng)建一次代理,這里再創(chuàng)建一次
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
  if (bean != null) {
    // TODO 這里后面重新過一下 Spring 創(chuàng)建 Bean 實例的步驟,傳進來的 beanName 是 alias 還是帶 & 的還是單純的 beanId
    // TODO 如果不是單純的 beanId ,這里可能會出錯
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    // 這里意味著前面通過這個提前拿到的地址。在調(diào)用 postProcessAfterInitialization() 包裹時發(fā)現(xiàn)傳進來的
    // 已經(jīng)和最開始的不一樣了。那就重新根據(jù)情況看是否要創(chuàng)建代理
    // TODO 這里能看出來和最開始暴露出去的不一樣了,估計解決循環(huán)依賴是否成功只有依賴一下兩種情況是否恰好發(fā)生:
    // 1. 沒有任何 Bean 引用了提前暴露出去的Bean
    // 2. 在后面的 getEarlyBeanReference() 的處理過程中有操作繼續(xù)包裹導(dǎo)致這里的不一致
    // TODO 其實這里想多了,上面的都是建立在假設(shè) earlyProxyReferences 就是暴露出去的對象,但是這里可以把它理解成一個記錄是否提前創(chuàng)建代理的記錄
    if (this.earlyProxyReferences.remove(cacheKey) != bean) {
      return wrapIfNecessary(bean, beanName, cacheKey);
    }
  }
  return bean;
}

思路很簡單,還是委托給wrapIfNecessary根據(jù)情況創(chuàng)建代理。只是之前可能做了提前暴露,用earlyProxyReferences緩存協(xié)助判斷看能否少走一步,加快構(gòu)造速度。

動態(tài)代理創(chuàng)建內(nèi)部邏輯記錄

wrapIfNecessary

上面我們對三個后處理的鉤子做了一些介紹,最后我們發(fā)現(xiàn)動態(tài)代理的創(chuàng)建基本委托給了wrapIfNecessary,當然也有更細致的委托,這里我們從這里入手對動態(tài)代理介紹,根據(jù)我先擼過一次的經(jīng)驗來說,從這里入手會把上面依賴的函數(shù)都過一遍。

直接放代碼:

// 如果這個 Bean 需要被代理,就代理一下
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  // this.targetSourcedBeans.contains(beanName) 表示此 beanName 對應(yīng)的 bean 沒有走正經(jīng) Spring 創(chuàng)建實例的過程
  // 直接搞定了。
  // TODO 這種創(chuàng)建方式貌似不走AOP的東西
  if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    return bean;
  }
  // 此 cacheKey 【通過 bean 實例得出】 之前做過判斷,根據(jù)之前的判斷是不用代理的
  if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    return bean;
  }
  // 如果滿足以下條件,則不對 bean 進行代理
  // 1. 此類是基礎(chǔ)類【配置代理相關(guān)的配置類】
  // 2. 或者根據(jù)用戶自定義的邏輯,不對它進行代理
  if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);// 這里做了緩存,方便有重復(fù)判斷時加快速度
    return bean;
  }

  // Create proxy if we have advice.
  // 得到 bean 對應(yīng)的增強方法,如果有需要增強的方法,則創(chuàng)建代理
  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  if (specificInterceptors != DO_NOT_PROXY) {
    this.advisedBeans.put(cacheKey, Boolean.TRUE);// 直接放進去,方便后續(xù)判斷
    // 已經(jīng)確定要創(chuàng)建代理,將創(chuàng)建工作進行委托
    Object proxy = createProxy(
      bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    // TODO 看一下這個緩存是怎么做的??代理臨時生成的類可以復(fù)用嗎??
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
  }
  // 已經(jīng)確定不用創(chuàng)建代理,緩存一下結(jié)果,方便后面的判斷
  this.advisedBeans.put(cacheKey, Boolean.FALSE);
  return bean;
}

思路如下:

3.png

我們主要介紹兩個函數(shù)即可:

  • getAdvicesAndAdvisorsForBean
  • createProxy

正好是我們最開始的postProcessBeforeInstantiation依賴的兩個。

getAdvicesAndAdvisorsForBean

直接上代碼:

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

  // 繼續(xù)委托
  List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  // 如果沒查到就返回特定值,方便判斷
  // TODO 感覺這種設(shè)計方法還是不太好的,一個返回值有了多種解讀語意,應(yīng)該是 Spring 為了接口簡潔做的一些妥協(xié)
  if (advisors.isEmpty()) {
    return DO_NOT_PROXY;
  }
  return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  // 獲得所有的增強器
  // 找出來,然后實例化
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  // 找到這個 bean 可以用的增強
  // 這里涉及針對 aop 篩選類、方法的東西
  List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  // 這里留一個鉤子,方便子類根據(jù)自己的需要進行增強器定制
  extendAdvisors(eligibleAdvisors);
  if (!eligibleAdvisors.isEmpty()) {
    eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  }
  return eligibleAdvisors;
}

還是老套路,繼續(xù)向外委托,本函數(shù)只做基礎(chǔ)的記錄和轉(zhuǎn)換。所以就一下子貼了兩個函數(shù)上去。整體思路還是比較清楚的:

  1. 先拿到所有的增強器
  2. 根據(jù)Bean篩選出可用的增強器
  3. 返回

我們接下來依次看這兩步的操作,先看第一步:拿到所有的增強器

// 返回 auto-proxy 中配置的所有的增強器
protected List<Advisor> findCandidateAdvisors() {
  Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
  // 委托給專門負責(zé)增強器檢索的類
  return this.advisorRetrievalHelper.findAdvisorBeans();
}

我們看findAdvisorBeans:

// 找到當前 BeanFactory 中所有的增強器
// TODO 注意,因為聲明增強器的方法太多了,我們挑通用邏輯。
// 不支持 FactoryBean。。。。正常人打@Aspect注解也不會專門搞個 FactoryBean , 保持類的功能純粹吧
// TODO 不支持正在實例化的bean。。。。這個再看
public List<Advisor> findAdvisorBeans() {
  // Determine list of advisor bean names, if not cached already.
  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!
    // 得到實現(xiàn)了 Advisor 接口的所有 beanId
    // 注意,這里傳了 false ,不會對 FactoryBean 進行初始化后再比
    // TODO  存疑,我們打的是 @Aspect 注解,什么時候轉(zhuǎn)化成對應(yīng)的 Advisor 類型的Bean了
    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) {
    if (isEligibleBean(name)) {
      // 等等,這個注意了,不是還沒初始化的 Bean ,是正在初始化的。想一下,有沒有什么問題?
      // TODO 是不是為了避免循環(huán)依賴???畢竟這里是配置類,如果配置類依賴了馬上要代理的單例(或者其他)類,解決循環(huán)依賴肯定是要失敗的吧
      // 所以,這里快刀斬亂麻,直接把這種危險依賴過濾掉了。雞賊啊
      if (this.beanFactory.isCurrentlyInCreation(name)) {
        if (logger.isDebugEnabled()) {
          logger.debug("Skipping currently created advisor '" + name + "'");
        }
      } else {
        try {
          // 都是創(chuàng)建好的或者還沒開始創(chuàng)建的,把他們實例化然后收集起來
          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.isDebugEnabled()) {
                logger.debug("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;
}

整體思路比較簡單,就是找出了BeanFactory中配置的所有的Advisor,然后實例化返回。

接下來看第二步:根據(jù)Bean篩選出可用的增強器

// 檢索增強器列表,找出所有可以用于 bean 代理的增強器
protected List<Advisor> findAdvisorsThatCanApply(
  List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
  // 使用 ThreadLocal 保存此線程正在生成代理的目標 beanId ,應(yīng)該是為了監(jiān)控及防止死循環(huán)吧
  ProxyCreationContext.setCurrentProxiedBeanName(beanName);
  try {
    // 老套路,處理完信息記錄、條件驗證之后,將要干的活委托給專門干這個活的人
    return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
  } finally {
    // 清除之前存儲的 beanId
    ProxyCreationContext.setCurrentProxiedBeanName(null);
  }
}

我們繼續(xù)深入看詳細的實現(xiàn)思路:

// 從入?yún)⒌脑鰪娖髁斜碇泻Y出入?yún)⒌腸lass可用的
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 判斷
    if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
      eligibleAdvisors.add(candidate);
    }
  }
  boolean hasIntroductions = !eligibleAdvisors.isEmpty();
  for (Advisor candidate : candidateAdvisors) {
    if (candidate instanceof IntroductionAdvisor) {
      // already processed
      continue;
    }
    // 非 IntroductionAdvisor 判斷是否可用
    if (canApply(candidate, clazz, hasIntroductions)) {
      eligibleAdvisors.add(candidate);
    }
  }
  return eligibleAdvisors;
}

這里分了兩種判斷,很簡單,因為Advisor分兩種:

  • IntroductionAdvisor只判斷到類級別
  • PointcutAdvisor判斷到方法級別

有興趣可以深入去看,不過根據(jù)猜測,我們用到的應(yīng)該都是第二種。

到這里,我們找出了所有可用的增強器。

createProxy

上面我們篩選出了合適的增強器,現(xiàn)在開始根據(jù)增強器構(gòu)建動態(tài)代理。

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

  //這里應(yīng)該是把代理處理之前的類進行保存
  if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
  }

  ProxyFactory proxyFactory = new ProxyFactory(); // 創(chuàng)建 ProxyFactory ,后面將用此對象通過傳進去的信息決定 JDK/CGLIB 的選擇
  proxyFactory.copyFrom(this);

  if (!proxyFactory.isProxyTargetClass()) { // 只有在沒有設(shè)置必須使用 CGLib 時才根據(jù)什么 BD字段、BD指定Class的接口進行判斷
    if (shouldProxyTargetClass(beanClass, beanName)) {
      proxyFactory.setProxyTargetClass(true);
    } else {
      evaluateProxyInterfaces(beanClass, proxyFactory);
    }
  }

  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()); // 代理的創(chuàng)建和獲取
}

我們在這個函數(shù)主要根據(jù)Bean實例的情況和配置進行判斷,并將判斷的結(jié)果設(shè)置到proxyFactory中,具體的創(chuàng)建操作委托給了proxyFactory

其實最關(guān)鍵的,這里做了一個判斷,設(shè)置了兩個屬性:

  • 判斷了創(chuàng)建代理的方式:CGLib還是JDK。
  • 設(shè)置了代理的目標實例,設(shè)置了動態(tài)代理的切面邏輯——增強器列表。

如果強制使用CGLib就直接使用,否則根據(jù)實例實現(xiàn)的接口判斷能否使用JDK:

protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
  // 得到此類實現(xiàn)的所有接口
  Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
  boolean hasReasonableProxyInterface = false;
  // 篩選一下接口,看有沒有可以用來代理的,如果有就可以考慮 JDK 動態(tài)代理了。如果沒有只能走 CGLIB
  for (Class<?> ifc : targetInterfaces) {

    // 1. 不能是那些 Spring 容器回調(diào)的接口
    // 2. 不能是那些本地鏈接庫的
    // 3. 接口不能是空的
    if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
        ifc.getMethods().length > 0) {
      hasReasonableProxyInterface = true;
      break;
    }
  }
  // 如果有符合條件的,就都存起來
  // TODO 這里沒有專門篩選那些,看看后面根據(jù)存的接口使用時有沒有過濾
  // TODO 感覺這里做的不是特別好
  if (hasReasonableProxyInterface) {
    // Must allow for introductions; can't just set interfaces to the target's interfaces only.
    for (Class<?> ifc : targetInterfaces) {
      proxyFactory.addInterface(ifc);
    }
  } else {
    // 沒有符合條件的接口,直接設(shè)置用 CGLIB 生成代理
    proxyFactory.setProxyTargetClass(true);
  }
}

這里整體的判斷思路還是比較清晰的。

至此,我們就把配置都設(shè)置到proxyFactory了,接下來我們看一下proxyFactory創(chuàng)建動態(tài)代理的策略。

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

protected final synchronized AopProxy createAopProxy() {
  if (!this.active) {
    activate();
  }
  return getAopProxyFactory().createAopProxy(this);
}

這里直接委托給了AopProxyFactory,我們繼續(xù)深入:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  // 如果有特殊配置或者類的情況要求用 CGLIB
  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.");
    }
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
      // 配置不合理,按照實際情況決定用 JDK 動態(tài)代理
      return new JdkDynamicAopProxy(config);
    }
    return new ObjenesisCglibAopProxy(config); // 否則根據(jù)配置用 CGLIB 動態(tài)代理
  } else { // 默認用 JDK 動態(tài)代理
    return new JdkDynamicAopProxy(config);
  }
}

思路很順暢,至此我們根據(jù)配置和具體的信息得到了一個JdkDynamicAopProxy或者一個ObjenesisCglibAopProxy

他們的工作原理下文會進行介紹。

擴展

Bean 后處理器相關(guān)介紹

BeanPostProcessor

提供了兩個針對Bean的處理鉤子,在調(diào)用初始化鉤子前后進行調(diào)用。

postProcessBeforeInitialization

調(diào)用場景:Bean填充屬性完成,在initializeBean()方法中先調(diào)用這個,再調(diào)用初始化的函數(shù)

返回結(jié)果:返回加工結(jié)果,如果返回null,后面的postProcessBeforeInitialization就不再調(diào)用了【同時,此后處理器返回的也不再被使用】

postProcessAfterInitialization:后處理器方法,可以在這里進行代理創(chuàng)建

調(diào)用場景:在initializeBean()方法中調(diào)用初始化的函數(shù)完成

返回結(jié)果:返回加工結(jié)果,如果返回null,后面的postProcessAfterInitialization就不再調(diào)用了【同時,此后處理器返回的也不再被使用】

InstantiationAwareBeanPostProcessor

繼承自上面的接口,新增兩個后處理鉤子用于在創(chuàng)建實例前后調(diào)用。

postProcessBeforeInstantiation:后處理器方法, 可以在這里直接創(chuàng)建出實例并完成代理創(chuàng)建,這里會阻塞后面的幾乎所有操作【創(chuàng)建實例/依賴注入/初始化】(阻塞我們介紹的那一大串的正常創(chuàng)建Bean的邏輯)

調(diào)用場景:在createBean()方法中調(diào)用,沒有返回結(jié)果才委托給doCreateBean()

返回結(jié)果:返回加工結(jié)果,如果返回結(jié)果不是null,后面的流程被全部繞過,直接調(diào)用postProcessAfterInitialization,然后返回 Bean 實例

postProcessAfterInstantiation

調(diào)用場景:走正常的創(chuàng)建邏輯,在創(chuàng)建完實例之后、填值之前調(diào)用

返回結(jié)果:返回加工結(jié)果,如果返回結(jié)果是false,不再繼續(xù)調(diào)用,且不再繼續(xù)調(diào)用填值操作

postProcessPropertyValues: 處理的主題不是 Bean 實例

調(diào)用場景:調(diào)用完上面的后處理器,找到合適的屬性值之后調(diào)用這個方法對值進行處理

返回結(jié)果:返回加工結(jié)果,如果返回結(jié)果是null,不再使用此屬性值進行屬性填充

SmartInstantiationAwareBeanPostProcessor

繼承自上買呢的接口,增加了用來預(yù)測創(chuàng)建 bean 的返回實例類型的方法。

predictBeanType:預(yù)測 Bean 的Class,感覺不是很重要的地方

determineCandidateConstructors:決定使用 bean 的構(gòu)造函數(shù),不再深入

getEarlyBeanReference:獲得 bean 的提前引用,用來解決循環(huán)引用,可以在這里進行代理創(chuàng)建。

調(diào)用場景:創(chuàng)建實例完成,是單例,需要先暴露實例以解決循環(huán)依賴再進行填值。調(diào)用此后處理器處理之后再暴露。

返回結(jié)果:返回加工結(jié)果,默認返回原對象。

問題遺留

參考文獻

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容