四、spring中高级装配(2)
? 這個是接著上一篇寫的,這章內容較多,分開來記錄一下。。。
三、處理自動裝配的歧義性
? 自動裝配讓spring完全負責bean引用注入到構造參數和屬性中,不過,僅有一個bean匹配所需的結果時,自動裝配才是有效的。如果不僅有一個bean能夠匹配的話,這種歧義性會阻礙spring自動裝配屬性、構造參數或方法參數。雖然這種歧義性十分罕見,但是我看了spring解決方法后,感覺spring提供的是一種這類問題的解決辦法,顯然在這里主要學習的是這種解決此類問題的思想。
//這里是提供了這種特殊情況的demo,有一個方法,需要自動裝配Dessert接口 @Autowired public void setDessert(Dessert dessert){this.dessert = dessert; } //但是這個Dessert接口卻有三個實現類,這就有點尷尬了,spring自動裝配的時候到底要裝配哪個實現類呢..... spring會報NoUniqueBeanDefinitionException錯誤的 @Component public class Cake implements Dessert{......}@Component public class Cookies implements Dessert{......}@Component public class IceCream implements Dessert{......}//使用@Primary 注解標注首選bean @Primary @Component public class IceCream implements Dessert{......}<bean id="iceCream" class="com.desserteater.IceCream" primary="true" />//但是兩個同時加上@Primary注解呢!!!spring中會有@Qualifier注解 @Autowired @Qualifier("iceCream") public void setDessert(Dessert dessert){this.dessert = dessert; } //但是這種方式使用的是bean ID,限制符與要注入的bean是緊耦合的,對類名稱的改動都會導致限定符失效,但是spring中允許為bean設置自己的限定符 @Component @Qualifier("cold") public class IceCream implements Dessert{......}@Autowired @Qualifier("cold") public void setDessert(Dessert dessert){this.dessert = dessert; }//但是如果是兩個實現類具有相同特點的限制符呢!!!這個考慮的也太全面了吧,程序員就是要有這種精神的,哈哈哈,就是下面這種情況呢..... @Component @Qualifier("cold") @Qualifier("creamy") public class IceCream implements Dessert{......}@Component @Qualifier("cold") @Qualifier("fruity") public class Popsicle implements Dessert{......}//Java 中不允許出現在同一個條目上出現相同類型的多個注解的,唉,終極辦法:自定義限制符注解,這個好牛叉牛叉... //這個對應著就是@Qualifier("cold") @Target({ElementType.CONSTRUCAOR, ElementType.FILELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier Public @interface Cold{}//這個對應著就是@Qualifier("creamy") @Target({ElementType.CONSTRUCAOR, ElementType.FILELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier Public @interface Creamy{}//這個對應著就是@Qualifier("fruity") @Target({ElementType.CONSTRUCAOR, ElementType.FILELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier Public @interface Fruity{}//大功告成,這就徹底解決那個問題了,你在有多少的我也不怕了,嘿嘿嘿,完美的解決這個問題了,spring中太美妙了,這種思想真的讓人受益匪淺 @Component @Cold @Creamy public class IceCream implements Dessert{......}@Component @Cold @Fruity public class Popsicle implements Dessert{......}@Autowired @Cold @Creamy public void setDessert(Dessert dessert){this.dessert = dessert; }四、bean的作用域
? ?在默認情況下,spring應用上下文中所有的bean都是以單例的形式創建的,也就是說,不管給定的一個bean被注入到其他bean多少次,每次所注入的都是同一個實例。大多數情況下,單例bean是很理想的方案。初始化和垃圾回收對線實例所帶來的成本只留給一些小規模的任務,在這些任務中,讓對象保持無狀態并且在應用中反復用這些對象可能并不合理。
spring中為解決這個問題,定義了多種作用域,可以基于這些作用域創建bean:
1)單例(Singleton):在整個應用中,只創建bean的一個實例
2)原型(Prototype):每次注入或者通過spring應用上下文獲取的時候,都會創建一個新的bean的實例
3)會話(Session):在web應用中,為每個會話創建一個bean實例
4)請求(Request):在web應用中,為每個請求創建一個bean實例
//Prototype 原型作用域的配置方式 @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class Notepad{......}<bean id="notepad" class="com.myapp.Notepad" scope="prototype" />//Session 會話和 Request 請求作用域 //在電商領域的 處理購物車bean 會話作用域是最合適的 @Component @Scope( value=WebApplicationContext.Scope.SESSION, ProxyMode=ScopedProxyMode.INTERFACES) Public ShoppingCart cart(){......}@Component Public class StoreService(){//StoreService是一個單例bean,會在spring應用上下文加載的時候創建,當它創建的時候,會試圖將ShoppingCart bean注入到set方法中,但是ShoppingCart bean是會話作用域,此時并不存在,直到某個用戶進入系統,創建會話之后才會出現ShoppingCart 的實例 @Autowiredpublic void setShoppingCart(ShoppingCart shoppingCart){this.shoppingCart = shoppingCart;} } /* 這里需要詳細講解一下ProxyMode 系統中,會有多個ShoppingCart 的實例,每個用戶一個,我們希望當StoreService處理購物車的時候,它所使用的ShoppingCart 實例恰好是當前會話所對應的那一個spring并不會將實際的ShoppingCart bean注入到StoreService中,spring會注入一個到ShoppingCart bean的代理,這個代理會暴露于ShoppingCart 相同的方法,StoreService會認為它就是一個購物車當StoreService 調用 ShoppingCart 的方法時,代理會對其進行懶解析并調用委托給會話作用域內真正的ShoppingCart bean這個東西好牛氣的樣子,這里涉及到了代理模式 *///注意:ScopedProxyMode.INTERFACES 表明這個代理要實現ShoppingCart接口,并將調用委托給實現bean //注意:ScopedProxyMode.TARGET_CLASS 實現的是一個具體的類的話,spring必須使用CGLib 來生成基于類的代理//XML中實現作用域的配置 這里用到了AOP Spring中面向切面 <bean id="cart" class="com.myapp.ShoppingCart"><aop:scoped=proxy /> //spring會默認CGLib創建目標類的代理 </bean>//這種 proxy-target-class="false" spring會創建基于接口的代理 <bean id="cart" class="com.myapp.ShoppingCart"><aop:scoped=proxy proxy-target-class="false" /> </bean>?五、運行時值注入
這節主要講的就是spring中的表達式語言SpEL,其他的基本上沒有特別重要的,值得思考的知識點。
spring提供了兩種在運行時求值的方式:
(1)屬性占位符(Property placeholder)
(2)Spring 表達式語言(SpEL)
屬性占位符的語法是:${.....}
主要來說一下Spring 表達式語言(SpEL)
1、SpEL擁有很多特性,主要包括:
1)使用bean的ID來應用bean
2)調用方法和訪問對象的屬性
3)對值進行算術、關系和邏輯運算
4)正則表達式匹配
5)集合操作
2、SpEL樣例
1)表示String值、浮點數、Boolean值
#{3.14159}
#{9.87E4}? 對應著 98700
#{“hello”}
#{true}
2)引用bean、屬性和方法
#{sgtPeppers}
#{sgtPeppers.artist}
#{sgtPeppers.selectArtist()}
#{sgtPeppers.selectArtist().toUpperCase()}
#{sgtPeppers.selectArtist()?.toUpperCase()}? 避免出現空值,出現?避免出現空值
3)在表達式中使用類型
T{java.lang.Math}
T{java.lang.Math}.PI
T{java.lang.Math}.random()
4)SpEL運算符
#{2*T{java.lang.Math}.PI*circle.radius}
#{T(java.lang.Math).PI*circle.radius^2}
#{disc.title + 'by' + disc.artist}
#{counter.total == 100}
#{counter.total eq 100}
#{score > 100 ? "winner" : "loser"}
5)計算正則表達式
#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9._]+\\.com'}
6)計算集合
#{jukebox.songs[4].title}
#{jukebox.songs[T(java.lang.Math).random * jukebox.songs.size()].title}
#{jukebox.songs.?[artist eq 'Aerosmith']} 過濾歌曲,得到所有屬性為Aerosmith的歌曲的小的集合
#{jukebox.songs.^[artist eq 'Aerosmith']}? 查詢集合中第一個屬性為Aerosmith的歌曲
#{jukebox.songs.![title]} 投影運算符,將集合中的特定的屬性放到一個新集合中去
#{jukebox.songs.?[artist eq 'Aerosmith']}.![title] 混合使用,把作者是Aerosmith的title屬性放到一個集合中去
轉載于:https://www.cnblogs.com/ssh-html/p/9656504.html
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的四、spring中高级装配(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 区分range() , np.arang
- 下一篇: consul之:ACL配置使用