在傳統(tǒng)Spring架構(gòu)中配置POJOs的基本操作有兩種:裝配和依賴注入。下面的例子中裝配了兩個(gè)POJO,同時(shí)指定了兩個(gè)對(duì)象之間的依賴關(guān)系。 例1:實(shí)現(xiàn)一個(gè)簡單類(Main.java)
package test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {private BasicService service;public BasicService getService() {return service;}public void setService(BasicService service) {this.service = service;}public void print() {service.print();}public static void main(String[] args) {String[] locations = { "beans.xml" };ApplicationContext ctx =new ClassPathXmlApplicationContext(locations);Main main = (Main)ctx.getBean("main");main.print();}}
例2:基本服務(wù)類(BasicService.java)
package test;public class BasicService {public void print() {System.out.println("success");}}
例3:在配置文件中的聲明(beans.xml)
<?xml version="1.0" encoding="UTF-8" ?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/beans"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="main" class="test.Main"><property name="service"><ref bean="service" /></property></bean><bean id="service" class="test.BasicService"></bean></beans>對(duì)于傳統(tǒng)裝配方式而言,最大的問題在于規(guī)模逐漸變大的項(xiàng)目中將會(huì)有越來越多的POJOs需要在XML文件中設(shè)置。這樣一方面無法迅速定位指定的對(duì)象,另一方面難于掌握對(duì)象之間的依賴關(guān)系。得益于Java5.0的注釋功能,到Spring2.5之后,其架構(gòu)中提供了一系列注釋,用于簡化裝配POJOs的過程。這種方式大大降低了傳統(tǒng)XML配置文件的管理成本,讓我們來看一下將上面的例子修改成注釋方式的樣子。
例4:注釋版Main.java
package test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.stereotype.Component;@Componentpublic class Main {@Autowiredprivate BasicService service;public void print() {service.print();}public static void main(String[] args) {String[] locations = { "beans.xml" };ApplicationContext ctx =new ClassPathXmlApplicationContext(locations);Main main = (Main) ctx.getBean("main");main.print();}}
例5:注釋版BasicService.java
package test;import org.springframework.stereotype.Component;@Component("service")public class BasicService {public void print() {System.out.println("success");}}
例6:注釋版beans.xml
<?xml version="1.0" encoding="UTF-8" ?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:component-scan base-package="test"></context:component-scan></beans>對(duì)于Spring架構(gòu)中的注釋功能而言,我們需要掌握哪些要點(diǎn)呢?
所有的Spring注釋中最重要的莫過于@Component,其作用就是在Spring容器中裝配一個(gè)POJO對(duì)象。@Component作用于類聲明之前,其用法有兩種:
@Component
@Component(“Spring容器內(nèi)的對(duì)象名”)
第一種注釋方法會(huì)在Spring容器中實(shí)例化一個(gè)以類名的首字母為小寫命名的POJO對(duì)象。如例4中對(duì)Main類的注釋將會(huì)在Spring容器中實(shí)例化一個(gè)名為main的POJO對(duì)象:
package test;...@Componentpublic class Main {...public static void main(String[] args) {String[] locations = { "beans.xml" };ApplicationContext ctx =new ClassPathXmlApplicationContext(locations);Main main = (Main)ctx.getBean("main");main.print();}}
當(dāng)然,如果不滿意類名首字母小寫的命名規(guī)則,第二種注釋方法允許我們自定義POJO的名稱。如例5中對(duì)BasicService的注釋:
package test;...@Component("service")public class BasicService {...}通常情況下保存在Spring容器中的POJOs有兩種形態(tài):singleton與prototype。@Component與@Scope配合即可指定不同的形態(tài)。@Scope緊隨@Component之后,其用法如下:
@Scope(“singleton”)
@Scope(“prototype”)
我們可以用下面的例子測試prototype或singleton形態(tài)的POJOs:
package test;import org.springframework.context.ApplicationContext;import org.springframework.context.annotation.Scope;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.stereotype.Component;@Component@Scope("prototype")public class Main {public void print() {System.out.println(toString());}public static void main(String[] args) {String[] locations = { "beans.xml" };ApplicationContext ctx =new ClassPathXmlApplicationContext(locations);Main main1 = (Main) ctx.getBean("main");main1.print();Main main2 = (Main) ctx.getBean("main");main2.print();System.out.println(main1 != main2);}}
與@Component對(duì)應(yīng),@Autowired用于Spring容器中POJOs之間的依賴注入操作,使用該注釋的最大好處是不必提供傳統(tǒng)JavaBeans的setter方法。如例4與例1相比,私有的成員變量service沒有提供settter方法,僅靠@Autowired就可以注入與之對(duì)應(yīng)的service對(duì)象。@Autowired作用于類的成員變量、類的setter方法或類的構(gòu)造函數(shù)。其用法有以下兩種:
@Autowired
@Autowired(required = false)
獨(dú)立的@Autowired以byType方式進(jìn)行依賴注入。如例4中對(duì)service成員變量的注釋:
package test;...@Componentpublic class Main {@Autowiredprivate BasicService service;...}
只要在Spring容器中存在一個(gè)(只有一個(gè))類型為test.BasicService的POJO時(shí),byType方式就可以正確注入。否則將拋出異常,如果不希望強(qiáng)制注入不存在的對(duì)象,可以使用第二種方式進(jìn)行注釋。如:
package test;...@Componentpublic class Main {@Autowired(required = false)private BasicService service;...}當(dāng)Spring容器中不存在相同類型的POJO對(duì)象時(shí),成員變量service將不進(jìn)行依賴注入操作。但是如果Spring容器中存在多個(gè)相同類型但名字不同的POJOs時(shí),又該如何處理呢?
@Autowired與@Qualifier配合使用時(shí)將會(huì)以byName方式進(jìn)行依賴注入。以byName方式進(jìn)行依賴注入正是為了避免相同類型的不同POJOs在注入時(shí)發(fā)生沖突。@Qualifier作用于類的成員變量、類的setter方法中的參數(shù)或類的構(gòu)造函數(shù)中的參數(shù),@Qualifier的用法如下:
@Qualifier(“Spring容器內(nèi)的對(duì)象名”)
如將例4的內(nèi)容修改一下。如下例:
package test;...@Componentpublic class Main {private BasicService service;@Autowiredpublic Main(@Qualifier("basicService")BasicService service) {this.service = service;}...}此時(shí)的成員變量只會(huì)從Spring容器中查找名字為service的POJO進(jìn)行注入。當(dāng)然如果定位到的POJO類型不符合要求或者相同名字的POJO在Spring容器中不存在,上述方法仍然會(huì)拋出異常。此時(shí)如有必要就需要@Autowired(required=false)來幫忙了。package test;
...@Componentpublic class Main {private BasicService service;@Autowiredpublic Main(@Qualifier("basicService")BasicService service) {this.service = service;}...}
與成員變量的依賴注入功能相似,@Autowired同樣可以通過構(gòu)造函數(shù)或setter方法進(jìn)行注入。如:
package test;...@Componentpublic class Main {private BasicService service;@Autowiredpublic Main(@Qualifier("basicService")BasicService service) {this.service = service;}...}
上述代碼中指明了在構(gòu)造函數(shù)中進(jìn)行依賴注入,同時(shí)指定參數(shù)service只接收名字為basicService的POJO。
為了使用Spring架構(gòu)中的注釋功能,例6所示的內(nèi)容是最小的配置要求。請(qǐng)注意XML根標(biāo)簽屬性中與傳統(tǒng)Spring配置文件的不同:
傳統(tǒng)配置文件
<?xml version="1.0" encoding="UTF-8" ?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/beans"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="main" class="test.Main"><property name="service"><ref bean="service" /></property></bean><bean id="service" class="test.BasicService"></bean></beans>
注釋用配置文件
<?xml version="1.0" encoding="UTF-8" ?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:component-scan base-package="test"></context:component-scan></beans>與傳統(tǒng)Spring配置文件相比,最大的不同在于配置文件中不必使用bean標(biāo)簽來裝配已經(jīng)使用了注釋的POJOs,配置文件的內(nèi)容將變得簡潔明了。
其中標(biāo)簽<context:component-scan/>的作用有兩點(diǎn):
1. 允許使用Spring架構(gòu)中的所有注釋功能,包括上述所有注釋;
2. 指定了需要掃描的類包,類包及其遞歸子包中所有的類都會(huì)被處理。
總之,Spring2.5的注釋功能可以極大的提高開發(fā)效率,使大量的維護(hù)工作得以簡化。我們沒有理由不掌握這樣的技術(shù)!
聯(lián)系客服