spring aop與注入

上一篇分析了兩種代理的大致原理堡牡,spring框架內的aop就是使用的這兩種代理模式则涯。spring在默認情況下可以根據被代理類是否實現接口自動切換代理方式复局,實現了接口使用jdk代理,沒實現接口使用cglib粟判。

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @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.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

    /**
     * Determine whether the supplied {@link AdvisedSupport} has only the
     * {@link org.springframework.aop.SpringProxy} interface specified
     * (or no proxy interfaces specified at all).
     */
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    }

}

然后如果我們在配置文件設置了<aop:aspectj-autoproxy proxy-target-class="true"/>后亿昏,“通常,指定{@code proxyTargetClass}來強制執(zhí)行CGLIB代理档礁,或指定一個或多個接口以使用JDK動態(tài)代理角钩。” 這是spring的注釋,意思是代理被強制指定cglib呻澜。

上面這段代碼發(fā)生在程序啟動時递礼,bean注入到DefaultListableBeanFactory的beanDefinitionNames里面,如果當前被注入的bean并沒有需要代理的標簽等羹幸,比如自定義aop脊髓,聲明式事務等,是不會走到這里的栅受,直接注入的就是相應的類将硝,而需要代理的會被包裝成代理注入進去恭朗。

然后接下來還是啟動過程中,會執(zhí)行bean的初始化的托管注入依疼,被@Autowiredd的bean會走一系列的步驟尋找出實例注入到當前初始化的bean痰腮。這一系列的動作鏈路很長,并且bean加載順序不同律罢,步驟略有不同诽嘉,debug出一種:
DefaultListableBeanFactory.resolveDependency()--DefaultListableBeanFactory.doResolveDependency()--DefaultListableBeanFactory.findAutowireCandidates()--BeanFactoryUtils.beanNamesForTypeIncludingAncestors()--
DefaultListableBeanFactory.getBeanNamesForType()--DefaultListableBeanFactory.doGetBeanNamesForType()--AbstractBeanFactory.isTypeMatch()--ResolvableType.isInstance()--ResolvableType.static ResolvableType forRawClass()--
ResolvableType.static ResolvableType forRawClass {}isAssignableFrom()--ResolvableType.getRawClass()--ClassUtils.isAssignable() retrun true or false。

ClassUtils.isAssignable()方法是native的方法弟翘,用來判斷是否可以轉型虫腋。
這樣分兩種情況:
1.proxy-target-class=false
一個沒實現接口的類,spring動態(tài)選擇使用了cglib代理稀余,被注入時TypeMatch時比較這個類和代理后他的子類悦冀,可以注入。

一個實現了接口的類睛琳,spring動態(tài)選擇使用了jdk代理盒蟆,當使用接口(如xxxService)注入時,TypeMatch時比較接口類和代理后的Proxy子類并實現了這個接口xxxService的類师骗,可以注入历等。

一個實現了接口的類,spring動態(tài)選擇使用了jdk代理辟癌,當使用實現類(如xxxServiceImpl)注入時寒屯,TypeMatch時比較實現類與代理后的Proxy子類并實現了這個接口xxxService的類,這時候是不通過的黍少,因為他們既不是父類子類的關系寡夹,也不是實現的關系,這會導致啟動失敗厂置,無法注入的錯誤菩掏。但是一般不會有人這么做,這是在我們項目里發(fā)現的做法昵济,導致不能使用動態(tài)選擇代理智绸,只能將proxy-target-class=true解決。
2.proxy-target-class=true
一個沒實現接口的類访忿,spring強制使用了cglib代理瞧栗,被注入時TypeMatch時比較這個類和代理后他的子類,可以注入醉顽。

一個實現了接口的類沼溜,spring強制使用了cglib代理平挑,當使用接口(如xxxService)注入時游添,TypeMatch時比較接口類和代理后的xxxServiceImpl類型的子類系草,可以注入。

一個實現了接口的類唆涝,spring強制使用了cglib代理找都,當使用實現類(如xxxServiceImpl)注入時,TypeMatch時比較xxxServiceImpl和代理后的xxxServiceImpl類型的子類廊酣,可以注入能耻。

所以配置文件中如何選擇proxy-target-class屬性,可根據具體代碼決定亡驰。


實際項目中晓猛,發(fā)現在配置文件applicationContext.xml中加了proxy-target-class=true后,實現類注入依然注入失敗凡辱,排查發(fā)現配置文件的component-scan配置有問題戒职。正常我們項目有兩個主要的配置文件,applicationContext.xml的父容器透乾,xxx-servlet.xml的mvc子容器配置文件洪燥。component-scan配置正確的方式是父容器掃描除了controller外的bean,然后mvc子容器僅掃描controller的bean乳乌。
父容器:

<context:component-scan base-package="com.storm">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

mvc子容器:

    <context:component-scan base-package="com.storm" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

這樣是正確的配置捧韵,也可以制定具體的包進行掃描,例如:

<context:component-scan base-package="com.storm.controller" />

我們項目在mvc的配置文件沒有加use-default-filters="false"汉操,如果不加這個配置再来,他會默認掃描全部4種注解,導致又一次的掃描到service注解磷瘤,serivce又被初始化了一遍其弊,并覆蓋之前初始化好的bean,而這個子容器的proxy-target-class沒有配置膀斋,為默認的false梭伐,所以導致了初始化失敗。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末仰担,一起剝皮案震驚了整個濱河市糊识,隨后出現的幾起案子,更是在濱河造成了極大的恐慌摔蓝,老刑警劉巖赂苗,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異贮尉,居然都是意外死亡拌滋,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門猜谚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來败砂,“玉大人赌渣,你說我怎么就攤上這事〔蹋” “怎么了坚芜?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斜姥。 經常有香客問我鸿竖,道長,這世上最難降的妖魔是什么铸敏? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任缚忧,我火速辦了婚禮,結果婚禮上杈笔,老公的妹妹穿的比我還像新娘搔谴。我一直安慰自己,他們只是感情好桩撮,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布敦第。 她就那樣靜靜地躺著,像睡著了一般店量。 火紅的嫁衣襯著肌膚如雪芜果。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天融师,我揣著相機與錄音右钾,去河邊找鬼。 笑死旱爆,一個胖子當著我的面吹牛舀射,可吹牛的內容都是我干的。 我是一名探鬼主播怀伦,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼脆烟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了房待?” 一聲冷哼從身側響起邢羔,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桑孩,沒想到半個月后拜鹤,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡流椒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年敏簿,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡惯裕,死狀恐怖温数,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情轻猖,我是刑警寧澤帆吻,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布域那,位于F島的核電站咙边,受9級特大地震影響,放射性物質發(fā)生泄漏次员。R本人自食惡果不足惜败许,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淑蔚。 院中可真熱鬧市殷,春花似錦、人聲如沸刹衫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽带迟。三九已至音羞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間仓犬,已是汗流浹背嗅绰。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留搀继,地道東北人窘面。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像叽躯,于是被迫代替她去往敵國和親财边。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內容