6.SpringAop之聲明式Aop基于配置:DefaultAdvisorAutoProxyCreator

這個類的設計,和Spring ioc的結合,簡直是吊炸天,實現了根據配置把spring ioc里面的bean替換為相應的代理對象,也為AspectJ的整合提供了支持,讓我們來看看Spring是如何做到這種更高級的聲明式Aop

1.類結構

DefaultAdvisorAutoProxyCreator類結構

這邊的講解線路分為2塊

  1. Spring的Bean后處理器,SmartInstantiationAwareBeanPostProcessor->InstantiationAwareBeanPostProcessor->BeanPostProcessor
  2. DefaultAdvisorAutoProxyCreator的主繼承線,DefaultAdvisorAutoProxyCreator->AbstractAdvisorAutoProxyCreator->AbstractAutoProxyCreator->ProxyProcessorSupport->ProxyConfig

講解之前可以看下我寫的這塊的demo ,可以一邊看解析,一邊打斷點調試

2.解析

2.1 Spring Bean后處理器

在講這三個接口之前,我們先來看下Spring bean的生命周期,不知道這個流程,也很難理解這三個接口的作用
閱讀AbstractAutowireCapableBeanFactory的doCreateBean和destroyBean方法,我們能清楚看到Spring bean創建的整個生命周期,具體如下

  1. 調用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
  2. bean實例化
  3. 調用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation(Object bean, String beanName)
  4. 調用InstantiationAwareBeanPostProcessor的postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
  5. bean注入properties
  6. 分別調用BeanNameAware,BeanClassLoaderAware,BeanFactoryAware中的方法
  7. 調用BeanPostProcessor的postProcessBeforeInitialization(Object bean, String beanName)
  8. 調用InitializingBean的afterPropertiesSet方法
  9. 調用自定義初始化方法
  10. 調用BeanPostProcessor的postProcessAfterInitialization(Object bean, String beanName)
  11. 調用DisposableBean的destroy()方法
  12. 調用自定義銷毀方法

下面分別介紹這三個bean后處理器的功能

public interface BeanPostProcessor {

    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
        
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

從生命周期中可以看到,BeanPostProcessor中的這兩個方法分別會在bean調用init方法前后回調,用于對已經注入properties的bean對象進行修改,把bean替換成代理對象會在postProcessAfterInitialization中執行

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;

}

postProcessBeforeInstantiation和postProcessAfterInstantiation分別在bean實例化前后回調
postProcessPropertyValues將在注入properties之前觸發,可以對整理好的properties進行修改

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
    Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException;

    Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException;

    Object getEarlyBeanReference(Object bean, String beanName) throws BeansException;

}

predictBeanType用于提前給出postProcessBeforeInstantiation生成的bean的類型
determineCandidateConstructors用于bean初始化的時候決定調用哪一個構造函數,如果針對某個類型的bean設置了這個回調,會采用回調設置的構造函數初始化bean,具體邏輯代碼如下

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

getEarlyBeanReference用于解決循環依賴的問題

這三個bean后處理器講解好了 ,現在我們開始講DefaultAdvisorAutoProxyCreator是怎么實現自動配置代理對象的

2.2 DefaultAdvisorAutoProxyCreator

從類結構圖中可以看到主要的繼承鏈,DefaultAdvisorAutoProxyCreator->AbstractAdivisorAutoProxyCreator->AbstractAutoProxyCreator->ProxyProcessorSupport->ProxyConfig
ProxyConfig就不多講了,之前講過,我們來分別介紹下其他4個類的作用

2.2.1 ProxyProcessorSupport

看名字就知道是一個為代理生成提供支持的工具類,主要提供evaluateProxyInterfaces方法用來根據BeanClass對ProxyFactory中的代理方式進行配置,方法如下

protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
        Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
        boolean hasReasonableProxyInterface = false;
        for (Class<?> ifc : targetInterfaces) {
            if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
                    ifc.getMethods().length > 0) {
                hasReasonableProxyInterface = true;
                break;
            }
        }
        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 {
            proxyFactory.setProxyTargetClass(true);
        }
    }

這里會判斷是否可以代理接口,如果可以,用proxyFactory的addInterface方法把設置所有存在的接口類,如果不可以,那么調用setProxyTargetClass(true),配置為代理類
同時我們可以注意到這個類實現了Ordered接口,并且設置order = Ordered.LOWEST_PRECEDENCE,這是為了讓生成代理的后處理器最后一個執行(原因可能是在之前的后處理器可能也會把Advisor加進去,那樣就會出現不生效的問題)

2.2.2 AbstractAutoProxyCreator

這個類是這個繼承鏈中最核心的類,因為生成代理的邏輯封裝在這里
它實現SmartInstantiationAwareBeanPostProcessor,在回調方法里封裝了把bean對象替換為代理對象的邏輯,在getEarlyBeanReference,postProcessBeforeInstantiation,postProcessAfterInitialization均能產生代理,postProcessBeforeInstantiation需要在配置了TargetSourceCreator之后才能生效,目前沒有遇到這個場景,所以忽略,getEarlyBeanReference是為了解決循環依賴重寫的,用來提前長生代理類,postProcessAfterInitialization在getEarlyBeanReference沒有生效的情況下會被調用,這兩個方法都調用了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;
        }

        // Create proxy if we have advice.
        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;
    }

wrapIfNecessary首先會通過getAdvicesAndAdvisorsForBean得到攔截器集合,這個會交給子類實現,子類可以設計不同的策略來獲取攔截器集合,如果getAdvicesAndAdvisorsForBean返回的集合不為空,就調用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 = new ProxyFactory();
        proxyFactory.copyFrom(this);

        if (!proxyFactory.isProxyTargetClass()) {
            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());
    }

createProxy還是比較熟悉的,在上節鋪墊過,使用了ProxyFactory的編程式Aop生成代理
通過這幾個回調,巧妙的在spring生命周期內把我們生成代理bean的行為注入了

2.2.3 AbstractAdivisorAutoProxyCreator

AbstractAdivisorAutoProxyCreator主要實現了AbstractAutoProxyCreator提供的擴展點方法getAdvicesAndAdvisorsForBean,用來設置攔截器集合

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

getAdvicesAndAdvisorsForBean中會通過findEligibleAdvisors來獲取攔截器集合,如果不存在返回DO_NOT_PROXY,來看下findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

protected List<Advisor> findCandidateAdvisors() {
        return this.advisorRetrievalHelper.findAdvisorBeans();
    }

在findEligibleAdvisors中,通過findCandidateAdvisors來獲取候選的adivisors,內部使用了advisorRetrievalHelper.findAdvisorBeans,其實就是從beanfactory獲取實現Advisor接口的bean,然后可以在這個方法里面看到

public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        String[] advisorNames = null;
        synchronized (this) {
            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!
                advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Advisor.class, true, false);
                this.cachedAdvisorBeanNames = advisorNames;
            }
        }
        if (advisorNames.length == 0) {
            return new LinkedList<Advisor>();
        }

        List<Advisor> advisors = new LinkedList<Advisor>();
        for (String name : advisorNames) {
            if (isEligibleBean(name)) {
                if (this.beanFactory.isCurrentlyInCreation(name)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipping currently created advisor '" + name + "'");
                    }
                }
                else {
                    try {
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                    }
                    catch (BeanCreationException ex) {
                        Throwable rootCause = ex.getMostSpecificCause();
                        if (rootCause instanceof BeanCurrentlyInCreationException) {
                            BeanCreationException bce = (BeanCreationException) rootCause;
                            if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
                                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;
    }

注意到有一個isEligibleBean方法,在AbstractAdivisorAutoProxyCreator使用了BeanFactoryAdvisorRetrievalHelper擴展子類,重定義了isEligibleBean方法,如下

private class BeanFactoryAdvisorRetrievalHelperAdapter extends BeanFactoryAdvisorRetrievalHelper {

        public BeanFactoryAdvisorRetrievalHelperAdapter(ConfigurableListableBeanFactory beanFactory) {
            super(beanFactory);
        }

        @Override
        protected boolean isEligibleBean(String beanName) {
            return AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);
        }
    }

把BeanFactoryAdvisorRetrievalHelper中的isEligibleBean委托給了AbstractAdvisorAutoProxyCreator實現,AbstractAdvisorAutoProxyCreator中默認實現如下

protected boolean isEligibleAdvisorBean(String beanName) {
        return true;
    }

這個實現默認為不過濾,可以讓子類去實現

2.2.4 DefaultAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator實現AbstractAdivisorAutoProxyCreator開放的擴展點isEligibleAdvisorBean,邏輯很簡單,如下

protected boolean isEligibleAdvisorBean(String beanName) {
        return (!isUsePrefix() || beanName.startsWith(getAdvisorBeanNamePrefix()));
    }

通過配置的prefix來過濾adivisor bean

2.3 InfrastructureAdvisorAutoProxyCreator

InfrastructureAdvisorAutoProxyCreator

InfrastructureAdvisorAutoProxyCreator也實現了AbstractAdivisorAutoProxyCreator開放的擴展點isEligibleAdvisorBean

@Override
   protected boolean isEligibleAdvisorBean(String beanName) {
       return (this.beanFactory.containsBeanDefinition(beanName) &&
               this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
   }

可以看到,這個過濾條件是,只選擇框架級別(beanDefinitiod的role為ROLE_INFRASTRUCTURE)的Adivisor來進行對符合條件的對象進行織入,生成代理

3.總結

DefaultAdvisorAutoProxyCreator主要實現的功能為使用bean后處理器的回調函數,根據ioc容器配置的advisor,來對ioc 容器中的其他bean生成相應代理

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,776評論 18 139
  • 如下是整篇文章的結構,所需閱讀時間大約20min Spring簡介 Spring框架由Rod Johnson開發,...
    李序鍇閱讀 903評論 0 15
  • Spring框架是由于軟件開發的復雜性而創建的。Spring使用的是基本的JavaBean來完成以前只可能由EJB...
    OSET我要編程閱讀 2,711評論 0 3
  • 昨天,和媽吵了一小架。一開始很生氣,唉!才說要好好陪她的。上班后想了想覺得真是對不起她老人家,不論媽怎么想...
    梁正媽媽閱讀 329評論 0 9
  • 前面介紹的組合繼承最大的問題就是無論什么情況下,都會調用兩次父類型的構造函數:一次是在創建子類型原型的時候,另一次...
    趙者也閱讀 326評論 0 0