spring AOP之走馬觀花

在:http://www.reibang.com/p/366c3aad046f
分析了整個IOC生成bean實例的流程宏怔,實際上拧烦,spring aop也是在IOC的基礎(chǔ)上去實現(xiàn)的。
在doCreateBean()方法的后半部分挠唆,也就是initializeBean方法中贿条,會通過BeanPostProcessor對Bean做加強:

    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 {
            // 調(diào)用aware方法 如 ApplicationConetxtAward之類的
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor前置處理
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 調(diào)用afterPropertySet等方法
            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后置處理
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 這里會通過postProcessAfterInitialization 方法對bean做一定的處理
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

這里會通過BeanPostProcessor雹仿,對bean做進一步的增強,而AOP的核心整以,就是一個BeanPostProcessor:


image.png

AbstractAutoProxyCreator 之 getEarlyBeanReference

在IOC中胧辽,為了解決單例模式下循環(huán)依賴的問題,spring會將實例化的bean提前暴露出來:

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

簡單來說就是通過SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference方法獲取增強后的bean公黑,而AbstractAutoProxyCreator同樣是SmartInstantiationAwareBeanPostProcessor的實現(xiàn)類邑商,其中實現(xiàn)了getEarlyBeanReference方法:

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return wrapIfNecessary(bean, beanName, cacheKey);
    }

這里面會將bean放入緩存中,然后通過wrapIfNecessary對bean進行AOP包裝凡蚜,并將包裝后的bean返回出去奠骄,wrapIfNecessary的邏輯我們后邊再說。

AbstractAutoProxyCreator 之 postProcessAfterInitialization

getEarlyBeanReference是為了解決提前暴露的問題番刊,而postProcessAfterInitialization則是AOP正常流程的入口:

    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            // 如果earlyProxyReferences中沒有bean 則 wrapIfNecessary
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

可以看到,如果earlyProxyReferences中不含有改bean影锈, 則remove一定會返null 從而執(zhí)行wrapIfNecessary對bean進行包裝芹务。

AOP包裝流程

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 關(guān)于targetSourcedBeans 先不去管它 有興趣可以自己查下
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        // 不需要創(chuàng)建 直接返回
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        //  這里shouldSkip也有加載所有advisor的作用
        // 有興趣可以去AspectJAwareAdvisorAutoProxyCreator類看下實現(xiàn)
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // 上面做了一些不需要創(chuàng)建代理的情況的判斷
        // 返回匹配當前 bean 的所有的 advisor蝉绷、advice、interceptor
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 創(chuàng)建代理
            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;
    }

這里會通過createProxy 方法創(chuàng)建代理對象:

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

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

        // 創(chuàng)建ProxyFactory 實例
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);

        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

        // 返回匹配了當前bean的Advisor
        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)建ProxyFactory并且通過proxyFactory.getProxy生成代理對象枣抱;

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

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

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        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 動態(tài)代理
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            // 如果有接口,會跑到這個分支
            return new JdkDynamicAopProxy(config);
        }
    }

大體上就是 實現(xiàn)了接口佳晶,則使用JDK動態(tài)代理桅狠,否則使用cglib動態(tài)代理。
后面兩個具體實現(xiàn)代理就不去細說了轿秧,有興趣的可以了解下jdk動態(tài)代理跟cglib是如何實現(xiàn)的中跌。

參考:
https://www.javadoop.com/post/spring-aop-source

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市菇篡,隨后出現(xiàn)的幾起案子漩符,更是在濱河造成了極大的恐慌,老刑警劉巖驱还,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗜暴,死亡現(xiàn)場離奇詭異,居然都是意外死亡议蟆,警方通過查閱死者的電腦和手機闷沥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咐容,“玉大人舆逃,你說我怎么就攤上這事∨北” “怎么了颖侄?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長享郊。 經(jīng)常有香客問我览祖,道長,這世上最難降的妖魔是什么炊琉? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任展蒂,我火速辦了婚禮,結(jié)果婚禮上苔咪,老公的妹妹穿的比我還像新娘锰悼。我一直安慰自己,他們只是感情好团赏,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布箕般。 她就那樣靜靜地躺著,像睡著了一般舔清。 火紅的嫁衣襯著肌膚如雪丝里。 梳的紋絲不亂的頭發(fā)上曲初,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音杯聚,去河邊找鬼臼婆。 笑死,一個胖子當著我的面吹牛幌绍,可吹牛的內(nèi)容都是我干的颁褂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼傀广,長吁一口氣:“原來是場噩夢啊……” “哼颁独!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起主儡,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤奖唯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后糜值,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丰捷,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年寂汇,在試婚紗的時候發(fā)現(xiàn)自己被綠了病往。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡骄瓣,死狀恐怖停巷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情榕栏,我是刑警寧澤畔勤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站扒磁,受9級特大地震影響庆揪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜妨托,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一缸榛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兰伤,春花似錦内颗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春负懦,著一層夾襖步出監(jiān)牢的瞬間筒捺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工纸厉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人五嫂。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓颗品,卻偏偏與公主長得像,于是被迫代替她去往敵國和親沃缘。 傳聞我的和親對象是個殘疾皇子躯枢,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容