javascript
第三章 最小化SpringXml 配置
自動(dòng)裝配(autowiring):有助于減少甚至消除<property>元素和<constructor-arg>元素,讓spring自動(dòng)識(shí)別如何裝配Bean的依賴關(guān)系。
自動(dòng)檢測(cè)(autodiscovery):比自動(dòng)裝配更進(jìn)一步,讓spring能夠自動(dòng)識(shí)別哪些類需要被裝配成sping Bean ,從而減少對(duì)<bean>元素的使用。
3.1 自動(dòng)裝配Bean屬性
3.1.1 4種類型的自動(dòng)裝配
byName——把與Bean的屬性具有相同的名字(或者ID)的其他Bean自動(dòng)裝配到Bean對(duì)應(yīng)的屬性中。如果沒有跟屬性的名字像匹配的Bean,則該屬性不進(jìn)行裝配。
byType——把與Bean的屬性具有相同類型的其他Bean自動(dòng)裝配到Bean的對(duì)應(yīng)屬性中,若果沒有跟屬性的類型相匹配的bean,則該屬性不被裝配。
constructor——把與Bean的構(gòu)造器入?yún)⒕哂邢嗤愋偷钠渌鸅ean自動(dòng)裝配到Bean構(gòu)造器的對(duì)應(yīng)參數(shù)中。
autodetect——首先嘗試使用constructor進(jìn)行自動(dòng)裝配,如果失敗,再嘗試使用byType進(jìn)行自動(dòng)裝配。
byName自動(dòng)裝配:
1 <!-- byName自動(dòng)裝配 2 缺點(diǎn):若是有多個(gè)音樂家需要裝配instrument屬性,則他們就會(huì)公用一個(gè)Saxopbone(即多個(gè)bean的屬性被同一個(gè)bean賦值) 3 --> 4 <!-- 先在容器中裝個(gè)樂器對(duì)象 --> 5 <bean id="instrument" class="com.springinaction.springidol.Saxophone"></bean> 6 <!--現(xiàn)在為音樂家kenny自動(dòng)裝配上面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自動(dòng)裝配,容器中若是有同個(gè)類型的多個(gè)bean,自動(dòng)裝配的時(shí)候,會(huì)出拋出異常(就像選擇性綜合征,多了不知選哪個(gè)了)NoUniqueBeanDefinitionException(不唯一bean定義異常,翻譯的可能不準(zhǔn)確):
1 <!-- byType裝配 2 有兩個(gè)樂器:kenny bean就不知道要識(shí)別那個(gè)樂器裝配給自己, 3 會(huì)拋出異常NoUniqueBeanDefinitionException(非唯一bean定義異常-個(gè)人翻譯,可能不正確), 4 但是下面會(huì)出現(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自動(dòng)裝配:
1 <!-- constructor 自動(dòng)裝配 2 這個(gè)要求PoeticJuggler類中有一個(gè)構(gòu)造器的參數(shù)是Sonnet29(他是--實(shí)現(xiàn)Poem的實(shí)現(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混合裝配,就不介紹了。
注:在測(cè)試代碼的時(shí)候,遇到了如下的SAXParseException異常:
Caused by: org.xml.sax.SAXParseException; lineNumber: 48; columnNumber: 45; 注釋中不允許出現(xiàn)字符串 "--"。
?? ?at ;
這個(gè)是由于springbean.xml中的注釋<!-- 這里是注釋 -->除了開頭和結(jié)尾可以有"--"外,里面不能有第三個(gè)"--",不如:<!-- 這里是是--注釋 -->就會(huì)報(bào)上面的錯(cuò)誤,這個(gè)一看就明白了。
3.1.2 默認(rèn)自動(dòng)裝配
若果需要為Spring應(yīng)用上下文中的額每一個(gè)Bean(或者其中大多數(shù))配置相同的autowire屬性,那么可以要求spring為它所創(chuàng)建的所有Bean引用相同的自動(dòng)裝配策略來(lái)簡(jiǎn)化配置
3.2 使用注解裝配
使用注解方式允許更細(xì)粒度的自動(dòng)裝配,我們可以選擇性標(biāo)注某一個(gè)屬性來(lái)對(duì)其應(yīng)用自動(dòng)裝配。spring容器默認(rèn)禁用注解裝配,所以,在使用基于注解的自動(dòng)裝配,我們需要在spring配置中啟用它。最簡(jiǎn)單的啟用方式是使用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;這兩個(gè)東西(好像是約束,不知是啥)
spring3支持幾種不同的用于自動(dòng)裝配的注解:
- spring自帶的@Autowierd注解;
- JSR-330的@Inject注解;
- JSR-250的@Resource注解;
3.2.1 使用@Autowired
@Autowired是:org.springframework.beans.factory.annotation包下的Autowired接口如下:
@Autowired的裝配代碼,比如,在Instrumentalist類型的setInstrument上標(biāo)注@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測(cè)試結(jié)果,這時(shí)容器中只有一個(gè)樂器類型的bean:
1 //測(cè)試注解@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當(dāng)springbean.xml中有兩個(gè)樂器類型的bean時(shí),會(huì)拋異常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,下面兩個(gè)bean同時(shí)存在的時(shí)候,會(huì)拋異常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可以在構(gòu)造器上面和屬性上面(這里標(biāo)注了就可以把setter方法刪掉了)都可以標(biāo)注;
當(dāng)容器中沒有自動(dòng)裝配的bean時(shí),會(huì)拋出 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
這時(shí)候@Autowired(required=false)這樣裝配,自動(dòng)裝配可選,容器中沒有改類型的bean,instrument值會(huì)是空:
? @Autowired(required=false)
?? ? private Instrument instrument;
這時(shí)候拋異常會(huì)拋NullPointException;
若是@Autowired注解用在構(gòu)造器上時(shí),只有一個(gè)構(gòu)造器上required設(shè)置為true,其他使用@Autowired注解所標(biāo)注的構(gòu)造器只能將required屬性設(shè)置為false。
為解決上述問題,可以使用注解@Qualifier("guitar"),配置如下,這種配置和第二章中的<property name='instrument' ref='guitar'>原理其實(shí)應(yīng)該差不多(個(gè)人覺得):
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還可以如下進(jìn)行配置:
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測(cè)試了一下<qualifier value="stringed"></qualifier>這個(gè)有沒有都可以哎,我用的spring版本是spring4.2.9的,難道版本高了,功能也自動(dòng)升級(jí)了,不是很明白:
?創(chuàng)建自定義的限定器(Qualifiler)(這個(gè)感覺好吊的樣子,因?yàn)榭床欢?#xff0c;感覺像是自己創(chuàng)建了個(gè)自定義的注解):
?首先創(chuàng)建一個(gè)接口:
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//好嘛?這應(yīng)該是自定義的注解吧 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 //測(cè)試注解@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如果有多個(gè)樂器類被@StringedInstrument標(biāo)注了,還需要再進(jìn)行細(xì)粒度的控制,感覺這個(gè)太麻煩!要自定義很多個(gè)限定器!
3.2.2 借助@Inject實(shí)現(xiàn)基于標(biāo)準(zhǔn)的自動(dòng)裝配
JSR-330是一種依賴注入規(guī)范,更常見的叫法at inject;
這個(gè)要用到新的jar文件,javax.inject,所以pom.xml文件中需要引入該jar依賴;
1 <!-- JSR-330的標(biāo)準(zhǔn)注解 --> 2 <dependency> 3 <groupId>javax.inject</groupId> 4 <artifactId>javax.inject</artifactId> 5 <version>1</version> 6 </dependency> View Code這個(gè)jar內(nèi)容如下,總共就這些類:
?
@Inject注解和@Autowired一樣,可以用來(lái)自動(dòng)裝配屬性、方法和構(gòu)造器;與@Autowired不同的是,@Inject沒有required屬性。
@Inject他也可以限定,用@Name,@Autowired用的@Qualifier:
1 @Inject 2 @Named("guitar") 3 private Instrument instrument; View Code基本用法和@Autowired差不多,@Name和@Qualifier區(qū)別:前者是通過Bean的ID來(lái)表示可選擇的Bean,后者是幫助我們縮小匹配Bean的選擇范圍(目前沒有感覺到太大的差一性);
3.2.3 在注解注入中使用表達(dá)式
Spring3.0引入了@Value,可以裝配String類型的值和基本類型的值,例如。
@Value("Eruption")
private String song;
@Value與SpEL表達(dá)式配合,才能顯示他的魔力(第二章中的SpEL表達(dá)式);
3.3 自動(dòng)檢測(cè)Bean
<context:annotation-config/>需要顯示定義<bean>,用<context:annotation-scan>允許spring自動(dòng)檢測(cè)Bean和定義Bean。為了配置Spring自動(dòng)檢測(cè),需要使用<context:conponent-scan>元素代替<context:annotation-config>元素,元素會(huì)掃描指定的包及其所有子包,并查處自動(dòng)注冊(cè)的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 為自動(dòng)檢測(cè)標(biāo)注Bean
<context:componment-scan>查找使用構(gòu)造型(stereotype)注解所標(biāo)注的類:
- @Component——通用的構(gòu)造型注解,標(biāo)識(shí)該類為Spring組件
- @Constroller——標(biāo)識(shí)將該類定義為SpringMVC controller
- @Repository——標(biāo)識(shí)將該類定義為數(shù)據(jù)倉(cāng)庫(kù)
- @Service——標(biāo)識(shí)將該類定義為服務(wù)
測(cè)試結(jié)果:
3.4 使用spring基于java的配置
3.4.1 創(chuàng)建基于Java的配置
即使Spring的java配置可以使用XML就可以編寫大多數(shù)的Spring配置,但是我們?nèi)匀恍枰獦O少量的XML來(lái)啟用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)建一個(gè)類,用@Configuration標(biāo)注該類,使用它標(biāo)注后,這個(gè)類就相當(dāng)于<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類,就等價(jià)于XML配置中的<beans> 7 //@Configuration注解會(huì)作為一個(gè)標(biāo)識(shí)告知Spring:這個(gè)類將包含一個(gè)多個(gè)SpringBean的定義。 8 //這些Bean的定義是使用@Bean注解所標(biāo)注的方法。 9 @Configuration 10 public class SpingIdolConfig { 11 12 /* 13 * 它等價(jià)于使用XML所配置的<bean>元素。@Bean告知Sping這個(gè)方法返回一個(gè)對(duì)象, 14 * 該對(duì)象應(yīng)該被注冊(cè)為Spring應(yīng)用上下文中的一個(gè)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("認(rèn)真的雪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此時(shí)Instrumentalist類是這樣的,兩個(gè)屬性的注解被注釋了:
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: 一個(gè)有天賦的音樂家 17 * @author mao 18 * @date 2017年3月19日 下午7:15:17 19 * 20 */ 21 //將該類注冊(cè)到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測(cè)試代碼:
1 //測(cè)試基于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結(jié)果:
這個(gè)基于java的注解,若是將上述的兩個(gè)注釋的注解解封:
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: 一個(gè)有天賦的音樂家 17 * @author mao 18 * @date 2017年3月19日 下午7:15:17 19 * 20 */ 21 //將該類注冊(cè)到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結(jié)果就是:
這個(gè)感覺像是就近原則啊(xml的注解在屬性上方),要么是先是執(zhí)行了基于java的配置,后又執(zhí)行了基于xml的配置,xml的配置覆蓋了前者的結(jié)果。
?源碼下載地址
轉(zhuǎn)載于:https://www.cnblogs.com/huaxueyihao/p/6594501.html
總結(jié)
以上是生活随笔為你收集整理的第三章 最小化SpringXml 配置的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017-3-19四校联考
- 下一篇: JS 键盘监听事件 enter 13