javascript
第三章 最小化SpringXml 配置
自動裝配(autowiring):有助于減少甚至消除<property>元素和<constructor-arg>元素,讓spring自動識別如何裝配Bean的依賴關系。
自動檢測(autodiscovery):比自動裝配更進一步,讓spring能夠自動識別哪些類需要被裝配成sping Bean ,從而減少對<bean>元素的使用。
3.1 自動裝配Bean屬性
3.1.1 4種類型的自動裝配
byName——把與Bean的屬性具有相同的名字(或者ID)的其他Bean自動裝配到Bean對應的屬性中。如果沒有跟屬性的名字像匹配的Bean,則該屬性不進行裝配。
byType——把與Bean的屬性具有相同類型的其他Bean自動裝配到Bean的對應屬性中,若果沒有跟屬性的類型相匹配的bean,則該屬性不被裝配。
constructor——把與Bean的構造器入?yún)⒕哂邢嗤愋偷钠渌鸅ean自動裝配到Bean構造器的對應參數(shù)中。
autodetect——首先嘗試使用constructor進行自動裝配,如果失敗,再嘗試使用byType進行自動裝配。
byName自動裝配:
1 <!-- byName自動裝配 2 缺點:若是有多個音樂家需要裝配instrument屬性,則他們就會公用一個Saxopbone(即多個bean的屬性被同一個bean賦值) 3 --> 4 <!-- 先在容器中裝個樂器對象 --> 5 <bean id="instrument" class="com.springinaction.springidol.Saxophone"></bean> 6 <!--現(xiàn)在為音樂家kenny自動裝配上面instrument的樂器--> 7 <bean id="kenny" --> 8 class="com.springinaction.springidol.Instrumentalist" 9 autowire="byName"> 10 <property name="song" value="演員——薛之謙"></property> 11 </bean> 12 13 <bean id="kenny1" 14 class="com.springinaction.springidol.Instrumentalist" 15 autowire="byName"> 16 <property name="song" value="演員1——薛之謙"></property> 17 </bean> View CodebyType自動裝配,容器中若是有同個類型的多個bean,自動裝配的時候,會出拋出異常(就像選擇性綜合征,多了不知選哪個了)NoUniqueBeanDefinitionException(不唯一bean定義異常,翻譯的可能不準確):
1 <!-- byType裝配 2 有兩個樂器:kenny bean就不知道要識別那個樂器裝配給自己, 3 會拋出異常NoUniqueBeanDefinitionException(非唯一bean定義異常-個人翻譯,可能不正確), 4 但是下面會出現(xiàn)提示: 5 org.springframework.beans.factory.UnsatisfiedDependencyException: 6 Error creating bean with name 'kenny' defined in class path resource [spring/springbean.xml]: Unsatisfied dependency expressed through bean property 'instrument': No qualifying bean of type [com.springinaction.springidol.Instrument] is defined: expected single matching bean but found 2: com.springinaction.springidol.Saxophone#0,com.springinaction.springidol.Guitar#0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.springinaction.springidol.Instrument] is defined: expected single matching bean but found 2: com.springinaction.springidol.Saxophone#0,com.springinaction.springidol.Guitar#0 7 Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.springinaction.springidol.Instrument] is defined: expected single matching bean but found 2: com.springinaction.springidol.Saxophone#0,com.springinaction.springidol.Guitar#0 8 --> 9 <!-- Saxophone類型的bean --> 10 <bean class="com.springinaction.springidol.Saxophone"></bean> 11 <!--Guitar類型的bean--> 12 <bean class="com.springinaction.springidol.Guitar"></bean> 13 14 <bean id="kenny" 15 class="com.springinaction.springidol.Instrumentalist" 16 autowire="byType"> 17 <property name="song" value="演員——薛之謙"></property> 18 </bean> View Codeconstructor自動裝配:
1 <!-- constructor 自動裝配 2 這個要求PoeticJuggler類中有一個構造器的參數(shù)是Sonnet29(他是--實現(xiàn)Poem的實現(xiàn)類)類型的 3 --> 4 <bean class="com.springinaction.springidol.Sonnet29"></bean> 5 6 <bean id="duke" 7 class="com.springinaction.springidol.PoeticJuggler" 8 autowire="constructor"/> View Code? autodetect混合裝配,就不介紹了。
注:在測試代碼的時候,遇到了如下的SAXParseException異常:
Caused by: org.xml.sax.SAXParseException; lineNumber: 48; columnNumber: 45; 注釋中不允許出現(xiàn)字符串 "--"。
?? ?at ;
這個是由于springbean.xml中的注釋<!-- 這里是注釋 -->除了開頭和結尾可以有"--"外,里面不能有第三個"--",不如:<!-- 這里是是--注釋 -->就會報上面的錯誤,這個一看就明白了。
3.1.2 默認自動裝配
若果需要為Spring應用上下文中的額每一個Bean(或者其中大多數(shù))配置相同的autowire屬性,那么可以要求spring為它所創(chuàng)建的所有Bean引用相同的自動裝配策略來簡化配置
3.2 使用注解裝配
使用注解方式允許更細粒度的自動裝配,我們可以選擇性標注某一個屬性來對其應用自動裝配。spring容器默認禁用注解裝配,所以,在使用基于注解的自動裝配,我們需要在spring配置中啟用它。最簡單的啟用方式是使用spring的context命名空間配置中的<context:annotation-config>元素:
spring的context命名空間:?xmlns:context="http://www.springframework.org/schema/context";
?xsi:schemaLocation的值中要加:http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd;這兩個東西(好像是約束,不知是啥)
spring3支持幾種不同的用于自動裝配的注解:
- spring自帶的@Autowierd注解;
- JSR-330的@Inject注解;
- JSR-250的@Resource注解;
3.2.1 使用@Autowired
@Autowired是:org.springframework.beans.factory.annotation包下的Autowired接口如下:
@Autowired的裝配代碼,比如,在Instrumentalist類型的setInstrument上標注@Autowired:
1 //注入樂器 2 @Autowired 3 public void setInstrument(Instrument instrument) { 4 this.instrument = instrument; 5 } View Code在springbean.xml中:
1 <!-- Saxophone類型的bean --> 2 <!-- <bean class="com.springinaction.springidol.Saxophone"></bean> --> 3 <!--Guitar類型的bean(Instrument 樂器)--> 4 <bean class="com.springinaction.springidol.Guitar"></bean> 5 6 <bean id="kenny" 7 class="com.springinaction.springidol.Instrumentalist"> 8 <property name="song" value="演員——薛之謙"></property> 9 </bean> View Code測試結果,這時容器中只有一個樂器類型的bean:
1 //測試注解@Autowired 2 @Test 3 public void testAutowired() throws Exception { 4 5 Instrumentalist kenny = (Instrumentalist) ac.getBean("kenny"); 6 kenny.perform(); 7 kenny.getInstrument().play(); 8 9 } View Code當springbean.xml中有兩個樂器類型的bean時,會拋異常BeanCreationException,還是bean不唯一的問題:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kenny': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.springinaction.springidol.Instrumentalist.setInstrument(com.springinaction.springidol.Instrument); nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.springinaction.springidol.Instrument] is defined: expected single matching bean but found 2: com.springinaction.springidol.Saxophone#0,com.springinaction.springidol.Guitar#0:
1 <!-- Saxophone類型的bean,下面兩個bean同時存在的時候,會拋異常NoUniqueBeanDefinitionException --> 2 <bean class="com.springinaction.springidol.Saxophone"></bean> 3 <!--Guitar類型的bean(Instrument 樂器)--> 4 <bean class="com.springinaction.springidol.Guitar"></bean> 5 6 <bean id="kenny" 7 class="com.springinaction.springidol.Instrumentalist"> 8 <property name="song" value="演員——薛之謙"></property> 9 </bean> View Code上面就拋出異常;
@Autowired可以在構造器上面和屬性上面(這里標注了就可以把setter方法刪掉了)都可以標注;
當容器中沒有自動裝配的bean時,會拋出 NoSuchBeanDefinitionException(沒有這樣的bean定義異常):
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.springinaction.springidol.Instrumentalist.setInstrument(com.springinaction.springidol.Instrument); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.springinaction.springidol.Instrument] found for
這時候@Autowired(required=false)這樣裝配,自動裝配可選,容器中沒有改類型的bean,instrument值會是空:
? @Autowired(required=false)
?? ? private Instrument instrument;
這時候拋異常會拋NullPointException;
若是@Autowired注解用在構造器上時,只有一個構造器上required設置為true,其他使用@Autowired注解所標注的構造器只能將required屬性設置為false。
為解決上述問題,可以使用注解@Qualifier("guitar"),配置如下,這種配置和第二章中的<property name='instrument' ref='guitar'>原理其實應該差不多(個人覺得):
1 @Autowired(required=false) 2 @Qualifier("guitar") 3 private Instrument instrument; View Code 1 <bean id="saxophone" class="com.springinaction.springidol.Saxophone"></bean> 2 <!--Guitar類型的bean(Instrument 樂器)--> 3 <bean id="guitar" class="com.springinaction.springidol.Guitar"></bean> 4 5 <bean id="kenny" 6 class="com.springinaction.springidol.Instrumentalist"> 7 <property name="song" value="演員——薛之謙"></property> 8 </bean> View Code還可以如下進行配置:
1 @Autowired(required=false) 2 //@Qualifier("guitar") 3 private Instrument instrument; View Code 1 package com.springinaction.springidol; 2 3 import org.springframework.beans.factory.annotation.Qualifier; 4 5 /** 6 * 7 * @ClassName: Guitar 8 * @Description: 樂器:吉他 9 * @author mao 10 * @date 2017年3月19日 下午8:15:44 11 * 12 */ 13 @Qualifier("stringed") 14 public class Guitar implements Instrument { 15 16 public Guitar(){ 17 18 } 19 20 public void play() { 21 System.out.println("guitar guitar guitar"); 22 } 23 24 } View Code 1 <bean class="com.springinaction.springidol.Guitar"> 2 <qualifier value="stringed"></qualifier> 3 </bean> 4 5 <bean id="kenny" 6 class="com.springinaction.springidol.Instrumentalist"> 7 <property name="song" value="演員——薛之謙"></property> 8 </bean> View Code測試了一下<qualifier value="stringed"></qualifier>這個有沒有都可以哎,我用的spring版本是spring4.2.9的,難道版本高了,功能也自動升級了,不是很明白:
?創(chuàng)建自定義的限定器(Qualifiler)(這個感覺好吊的樣子,因為看不懂,感覺像是自己創(chuàng)建了個自定義的注解):
?首先創(chuàng)建一個接口:
1 package com.springinaction.springidol; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 import org.springframework.beans.factory.annotation.Qualifier; 9 10 @Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE}) 11 @Retention(RetentionPolicy.RUNTIME) 12 @Qualifier 13 public @interface StringedInstrument { 14 15 } View Code 1 package com.springinaction.springidol; 2 3 4 /** 5 * 6 * @ClassName: Guitar 7 * @Description: 樂器:吉他 8 * @author mao 9 * @date 2017年3月19日 下午8:15:44 10 * 11 */ 12 @StringedInstrument//好嘛?這應該是自定義的注解吧 13 public class Guitar implements Instrument { 14 15 public Guitar(){ 16 17 } 18 19 public void play() { 20 System.out.println("guitar guitar guitar"); 21 } 22 23 } View Code 1 @Autowired 2 //@Qualifier("guitar") 3 @StringedInstrument 4 private Instrument instrument; View Code 1 <bean class="com.springinaction.springidol.Guitar"> 2 <!-- <qualifier value="stringed"></qualifier> 這一行有沒有不影響 --> 3 </bean> 4 5 <bean id="kenny" 6 class="com.springinaction.springidol.Instrumentalist"> 7 <property name="song" value="演員——薛之謙"></property> 8 </bean> View Code 1 //測試注解@Autowired @StringedInstrument 2 @Test 3 public void testAutowired() throws Exception { 4 5 Instrumentalist kenny = (Instrumentalist) ac.getBean("kenny"); 6 kenny.perform(); 7 kenny.getInstrument().play(); 8 9 } View Code如果有多個樂器類被@StringedInstrument標注了,還需要再進行細粒度的控制,感覺這個太麻煩!要自定義很多個限定器!
3.2.2 借助@Inject實現(xiàn)基于標準的自動裝配
JSR-330是一種依賴注入規(guī)范,更常見的叫法at inject;
這個要用到新的jar文件,javax.inject,所以pom.xml文件中需要引入該jar依賴;
1 <!-- JSR-330的標準注解 --> 2 <dependency> 3 <groupId>javax.inject</groupId> 4 <artifactId>javax.inject</artifactId> 5 <version>1</version> 6 </dependency> View Code這個jar內(nèi)容如下,總共就這些類:
?
@Inject注解和@Autowired一樣,可以用來自動裝配屬性、方法和構造器;與@Autowired不同的是,@Inject沒有required屬性。
@Inject他也可以限定,用@Name,@Autowired用的@Qualifier:
1 @Inject 2 @Named("guitar") 3 private Instrument instrument; View Code基本用法和@Autowired差不多,@Name和@Qualifier區(qū)別:前者是通過Bean的ID來表示可選擇的Bean,后者是幫助我們縮小匹配Bean的選擇范圍(目前沒有感覺到太大的差一性);
3.2.3 在注解注入中使用表達式
Spring3.0引入了@Value,可以裝配String類型的值和基本類型的值,例如。
@Value("Eruption")
private String song;
@Value與SpEL表達式配合,才能顯示他的魔力(第二章中的SpEL表達式);
3.3 自動檢測Bean
<context:annotation-config/>需要顯示定義<bean>,用<context:annotation-scan>允許spring自動檢測Bean和定義Bean。為了配置Spring自動檢測,需要使用<context:conponent-scan>元素代替<context:annotation-config>元素,元素會掃描指定的包及其所有子包,并查處自動注冊的Spring Bean的類。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-4.0.xsd"> 10 <context:component-scan 11 base-package="com.springinaction.springidol"> </context:component-scan> 12 </beans> View Code3.3.1 為自動檢測標注Bean
<context:componment-scan>查找使用構造型(stereotype)注解所標注的類:
- @Component——通用的構造型注解,標識該類為Spring組件
- @Constroller——標識將該類定義為SpringMVC controller
- @Repository——標識將該類定義為數(shù)據(jù)倉庫
- @Service——標識將該類定義為服務
測試結果:
3.4 使用spring基于java的配置
3.4.1 創(chuàng)建基于Java的配置
即使Spring的java配置可以使用XML就可以編寫大多數(shù)的Spring配置,但是我們?nèi)匀恍枰獦O少量的XML來啟用Java配置:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-4.0.xsd"> 10 <context:component-scan 11 base-package="com.springinaction.springidol*"></context:component-scan> 12 13 </beans> View Code首先創(chuàng)建一個類,用@Configuration標注該類,使用它標注后,這個類就相當于<beans>容器了:
1 package com.springinaction.springidol; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Configuration; 5 6 //在基于java的配置里使用@Configuration注解java類,就等價于XML配置中的<beans> 7 //@Configuration注解會作為一個標識告知Spring:這個類將包含一個多個SpringBean的定義。 8 //這些Bean的定義是使用@Bean注解所標注的方法。 9 @Configuration 10 public class SpingIdolConfig { 11 12 /* 13 * 它等價于使用XML所配置的<bean>元素。@Bean告知Sping這個方法返回一個對象, 14 * 該對象應該被注冊為Spring應用上下文中的一個Bean。方法名將作為該Bean的ID 15 */ 16 @Bean 17 public Performer duke(){ 18 return new Juggler(); 19 } 20 21 @Bean 22 public Performer kenny(){ 23 24 Instrumentalist kenny = new Instrumentalist(); 25 kenny.setSong("認真的雪Bean----薛之謙"); 26 kenny.setInstrument(guitar()); 27 return kenny; 28 29 } 30 31 @Bean 32 public Instrument guitar(){ 33 return new Guitar(); 34 } 35 36 } View Code此時Instrumentalist類是這樣的,兩個屬性的注解被注釋了:
1 package com.springinaction.springidol; 2 3 import javax.inject.Inject; 4 import javax.inject.Named; 5 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.beans.factory.annotation.Qualifier; 8 import org.springframework.beans.factory.annotation.Value; 9 import org.springframework.stereotype.Component; 10 11 12 13 /** 14 * 15 * @ClassName: Instrumentalist 16 * @Description: 一個有天賦的音樂家 17 * @author mao 18 * @date 2017年3月19日 下午7:15:17 19 * 20 */ 21 //將該類注冊到Spring容器中,顯示的為其命名為eddie。即ID為eddie 22 23 public class Instrumentalist implements Performer { 24 25 // @Value("演員---薛之謙") 26 private String song; 27 28 // @Autowired 29 // @Qualifier("saxophone") 30 private Instrument instrument; 31 32 //注入樂器 33 public void setInstrument(Instrument instrument) { 34 this.instrument = instrument; 35 } 36 public Instrument getInstrument() { 37 return instrument; 38 } 39 //注入歌曲 40 public void setSong(String song) { 41 this.song = song; 42 } 43 public String getSong() { 44 return song; 45 } 46 47 public Instrumentalist(){ 48 49 } 50 51 public void perform() throws Exception { 52 System.out.println("Playing "+song+": "); 53 } 54 55 } View Code測試代碼:
1 //測試基于java的配置 2 @Test 3 public void testJava() throws Exception { 4 5 Instrumentalist eddie = (Instrumentalist) ac.getBean("kenny"); 6 eddie.perform(); 7 eddie.getInstrument().play(); 8 9 } View Code結果:
這個基于java的注解,若是將上述的兩個注釋的注解解封:
1 package com.springinaction.springidol; 2 3 import javax.inject.Inject; 4 import javax.inject.Named; 5 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.beans.factory.annotation.Qualifier; 8 import org.springframework.beans.factory.annotation.Value; 9 import org.springframework.stereotype.Component; 10 11 12 13 /** 14 * 15 * @ClassName: Instrumentalist 16 * @Description: 一個有天賦的音樂家 17 * @author mao 18 * @date 2017年3月19日 下午7:15:17 19 * 20 */ 21 //將該類注冊到Spring容器中,顯示的為其命名為eddie。即ID為eddie 22 23 public class Instrumentalist implements Performer { 24 25 @Value("演員---薛之謙") 26 private String song; 27 28 @Autowired 29 @Qualifier("saxophone") 30 private Instrument instrument; 31 32 //注入樂器 33 public void setInstrument(Instrument instrument) { 34 this.instrument = instrument; 35 } 36 public Instrument getInstrument() { 37 return instrument; 38 } 39 //注入歌曲 40 public void setSong(String song) { 41 this.song = song; 42 } 43 public String getSong() { 44 return song; 45 } 46 47 public Instrumentalist(){ 48 49 } 50 51 public void perform() throws Exception { 52 System.out.println("Playing "+song+": "); 53 } 54 55 } View Code結果就是:
這個感覺像是就近原則啊(xml的注解在屬性上方),要么是先是執(zhí)行了基于java的配置,后又執(zhí)行了基于xml的配置,xml的配置覆蓋了前者的結果。
?源碼下載地址
轉載于:https://www.cnblogs.com/huaxueyihao/p/6594501.html
總結
以上是生活随笔為你收集整理的第三章 最小化SpringXml 配置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017-3-19四校联考
- 下一篇: 通讯录链表实现之C++