Spring註解@Component、@Repository、@Service、@Controller區別

Spring註解@Component@Repository@Service@Controller區別

Spring 2.5 中除了提供 @Component 註釋外,還定義了幾個擁有特殊語義的註釋,它們分別是:@Repository@Service @Controller。在目前的 Spring 版本中,這 3 個註釋和 @Component 是等效的,但是從註釋類的命名上,很容易看出這 3 個註釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個註釋和 @Component 相比沒有什麼新意,但 Spring 將在以後的版本中爲它們添加特殊的功能。所以,如果 Web 應用程序採用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別採用 @Repository@Service @Controller 對分層中的類進行註釋,而用 @Component 對那些比較中立的類進行註釋。 

在一個稍大的項目中,通常會有上百個組件,如果這些組件採用xmlbean定義來配置,顯然會增加配置文件的體積,查找以及維護起來也不太方便。 Spring2.5爲我們引入了組件自動掃描機制,他可以在類路徑底下尋找標註了@Component,@Service,@Controller,@Repository註解的類,並把這些類納入進spring容器中管理。它的作用和在xml文件中使用bean節點配置組件時一樣的。要使用自動掃描機制,我們需要打開以下配置信息: 
Java
代碼 

1. <?xml version="1.0" encoding="UTF-8" ?> <beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-2.5.xsd"
 
2. >
 
3.  
 
4. <context:component-scan base-package=”com.eric.spring”>  
 
5. </beans>  
 
6.
其中base-package爲需要掃描的包(含所有子包) @Service用於標註業務層組件,@Controller用於標註控制層組件(如struts中的action,@Repository用於標註數據訪問組件,即DAO組件,而@Component泛指組件,當組件不好歸類的時候,我們可以使用這個註解進行標註。   
7. @Service public class VentorServiceImpl implements iVentorService{  
 
8. } @Repository public class VentorDaoImpl implements iVentorDao {
 
9. } getBean
的默認名稱是類名(頭字母小寫),如果想自定義,可以@Service(“aaaaa”)這樣來指定,這種bean默認是單例的,如果想改變,可以使用@Service(“beanName”)@Scope(“prototype”)來改變。可以使用以下方式指定初始化方法和銷燬方法(方法名任意): @PostConstructpublic void init() { 
10. }
 
11. @PreDestroy public void destory() {
 
12. }
 



注入方式: 

DAO實現類注入到service實現類中,把service的接口(注意不要是service的實現類)注入到action中,注 

入時不要new 這個注入的類,因爲spring會自動注入,如果手動再new的話會出現錯誤,然後屬性加上 

@Autowired
後不需要getter()setter()方法,Spring也會自動注入。至於更具體的內容,等對注入的方式更 

加熟練後會做個完整的例子上來。 

註解: 

spring的配置文件裏面只需要加上<context:annotation-config/><context:component-scanbase-package="需要實現注入的類所在包"/>,可以使用base-package="*"表示全部的類。   

<context:component-scan base-package=”com.eric.spring”>
 

其中base-package爲需要掃描的包(含所有子包) 

在接口前面標上@Autowired@Qualifier註釋使得接口可以被容器注入,當接口存在兩個實現類的時候必須指定其中一個來注入,使用實現類首字母小寫的字符串來注入,如: 

    @Autowired     
 
  
 
    @Qualifier("chinese")      
 
  
 
     private Man man;   
 
否則可以省略,只寫@Autowired   

@Service
服務層組件,用於標註業務層組件,表示定義一個bean,自動根據bean的類名實例化一個首寫字母爲小寫的bean,例如Chinese實例化爲chinese,如果需要自己改名字則:@Service("你自己改的bean")   

@Controller
用於標註控制層組件(struts中的action) 

@Repository
持久層組件,用於標註數據訪問組件,即DAO組件 

@Component
泛指組件,當組件不好歸類的時候,我們可以使用這個註解進行標註。 


@Service
 
public class VentorServiceImpl implements iVentorService {
 
}
 

@Repository
 
public class VentorDaoImpl implements iVentorDao {
 
}
 

getBean
的默認名稱是類名(頭字母小寫),如果想自定義,可以@Service(“aaaaa”) 這樣來指定,這種 

bean
默認是單例的,如果想改變,可以使用@Service(“beanName”)@Scope(“prototype”)來改變。 

可以使用以下方式指定初始化方法和銷燬方法(方法名任意): 

@PostConstruct
 

public void init() {
 

}
 

@PreDestroy
 

public void destory() {
 

}
 

 

 

 

 

Spring@Autowired註解、@Resource註解的區別

BY ETHAN ON 2011 06 02  IN JAVA

Spring不但支持自己定義的@Autowired註解,還支持幾個由JSR-250規範定義的註解,它們分別是@Resource@PostConstruct以及@PreDestroy
@Resource的作用相當於@Autowired,只不過@AutowiredbyType自動注入,而@Resource默認按 byName自動注入罷了。@Resource有兩個屬性是比較重要的,分是nametypeSpring@Resource註解的name屬性解析爲bean的名字,而type屬性則解析爲bean的類型。所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。
@Resource裝配順序
1. 如果同時指定了nametype,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常
2. 如果指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
3. 如果指定了type,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常
4. 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有匹配,則回退爲一個原始類型進行匹配,如果匹配則自動裝配;

@Autowired @Resource的區別:

 

1 @Autowired@Resource都可以用來裝配bean.都可以寫在字段上,或寫在setter方法上。

2 @Autowired默認按類型裝配(這個註解是屬業spring的),默認情況下必須要求依賴對象必須存在,如果要允許null值,可以設置它的required屬性爲false,如:@Autowired(required=false),如果我們想使用名稱裝配可以結合@Qualifier註解進行使用,如下:

1

@Autowired() @Qualifier("baseDao")

2

private BaseDao baseDao;

3@Resource(這個註解屬於J2EE的),默認安裝名稱進行裝配,名稱可以通過name屬性進行指定,如果沒有指定name屬性,當註解寫在字段上時,默認取字段名進行安裝名稱查找,如果註解寫在setter方法上默認取屬性名進行裝配。當找不到與名稱匹配的bean時才按照類型進行裝配。但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進行裝配。

1

@Resource(name="baseDao")

2

private BaseDao baseDao;

推薦使用:@Resource註解在字段上,這樣就不用寫setter方法了,並且這個註解是屬於J2EE的,減少了與spring的耦合。這樣代碼看起就比較優雅

 

 

 

 

 

 

1.  使用Spring2.5Autowired實現註釋型的IOC  

2.     

3.  本文地址:http://qzone.qq.com/blog/55357655-1232078233   

4.    

5.    使用Spring2.5的新特性——Autowired可以實現快速的自動注入,而無需在xml文檔裏面添加bean的聲明,大大減少了xml文檔的維護。(偶喜歡這個功能,因爲偶對xml不感冒)。       以下是一個例子:  

6.  先編寫接口Man  

7.         public interface Man {  

8.             public String sayHello();  

9.  }  

10. 然後寫Man的實現類ChineseAmerican  

11.        @Service  

12. public class Chinese implements Man{  

13.     public String sayHello() {  

14.         return "I am Chinese!";  

15.     }  

16. }  

17.   

18.        @Service  

19. public class American implements Man{  

20.     public String sayHello() {  

21.         return "I am American!";  

22.     }  

23. }  

24.   

25. @Service註釋表示定義一個bean,自動根據bean的類名實例化一個首寫字母爲小寫的bean,例如Chinese實例化爲chineseAmerican實例化爲american,如果需要自己改名字則:@Service("你自己改的bean")  

26.   

27. beans.xml  

28. <?xml version="1.0" encoding="UTF-8"?>  

29. <beans xmlns="http://www.springframework.org/schema/beans"  

30.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

31.         xmlns:context="http://www.springframework.org/schema/context"  

32.         xsi:schemaLocation="http://www.springframework.org/schema/beans   

33.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  

34.            http://www.springframework.org/schema/context  

35.            http://www.springframework.org/schema/context/spring-context-2.5.xsd">  

36.       <context:annotation-config/>  

37.       <context:component-scan base-package="testspring.main"/>  

38. </beans>  

39. spring的配置文件裏面只需要加上<context:annotation-config/><context:component-scan base-package="需要實現注入的類所在包"/>,可以使用base-package="*"表示全部的類。  

40.   

41. 編寫主類測試:  

42. @Service  

43. public class Main {  

44.     @Autowired  

45.     @Qualifier("chinese")  

46.     private Man man;  

47.   

48.     public static void main(String[] args) {  

49.         // TODO code application logic here  

50.         ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");  

51.         Main main = (Main) ctx.getBean("main");  

52.         System.out.println(main.getMan().sayHello());  

53.     }  

54.   

55.     public Man getMan() {  

56.         return man;  

57.     }  

58. }  

59.   

60. Man接口前面標上@Autowired@Qualifier註釋使得Man接口可以被容器注入,當Man接口存在兩個實現類的時候必須指定其中一個來注入,使用實現類首字母小寫的字符串來注入。否則可以省略,只寫@Autowired   

61.   

62. **********************  

63. 使用 Spring 2.5 註釋驅動的 IoC 功能  

64. 發表於08-03-04 20:38 | 閱讀 1285 | 評分 (暫無)   

65. 概述  

66.   

67. 註釋配置相對於 XML 配置具有很多的優勢:  

68.   

69. 它可以充分利用 Java 的反射機制獲取類結構信息,這些信息可以有效減少配置的工作。如使用 JPA 註釋配置 ORM 映射時,我們就不需要指定 PO 的屬性名、類型等信息,如果關係表字段和 PO 屬性名、類型都一致,您甚至無需編寫任務屬性映射信息——因爲這些信息都可以通過 Java 反射機制獲取。   

70. 註釋和 Java 代碼位於一個文件中,而 XML 配置採用獨立的配置文件,大多數配置信息在程序開發完成後都不會調整,如果配置信息和 Java 代碼放在一起,有助於增強程序的內聚性。而採用獨立的 XML 配置文件,程序員在編寫一個功能時,往往需要在程序文件和配置文件中不停切換,這種思維上的不連貫會降低開發效率。   

71. 因此在很多情況下,註釋配置比 XML 配置更受歡迎,註釋配置有進一步流行的趨勢。Spring 2.5 的一大增強就是引入了很多註釋類,現在您已經可以使用註釋配置完成大部分 XML 配置的功能。在這篇文章裏,我們將向您講述使用註釋進行 Bean 定義和依賴注入的內容。  

72.   

73.  

74. 原來我們是怎麼做的  

75.   

76. 在使用註釋配置之前,先來回顧一下傳統上是如何配置 Bean 並完成 Bean 之間依賴關係的建立。下面是 3 個類,它們分別是 OfficeCar  Boss,這 3 個類需要在 Spring 容器中配置爲 Bean  

77.   

78. Office 僅有一個屬性:  

79.   

80.   

81. 清單 1. Office.java  

82.                   

83. package com.baobaotao;  

84. public class Office {  

85.     private String officeNo =”001”;  

86.   

87.     //省略 get/setter  

88.   

89.     @Override  

90.     public String toString() {  

91.         return "officeNo:" + officeNo;  

92.     }  

93. }  

94.    

95.   

96.   

97. Car 擁有兩個屬性:  

98.   

99.   

100.  清單 2. Car.java  

101.                    

102.  package com.baobaotao;  

103.    

104.  public class Car {  

105.      private String brand;  

106.      private double price;  

107.    

108.      // 省略 get/setter  

109.    

110.      @Override  

111.      public String toString() {  

112.          return "brand:" + brand + "," + "price:" + price;  

113.      }  

114.  }  

115.     

116.    

117.    

118.  Boss 擁有 Office  Car 類型的兩個屬性:  

119.    

120.    

121.  清單 3. Boss.java  

122.                    

123.  package com.baobaotao;  

124.    

125.  public class Boss {  

126.      private Car car;  

127.      private Office office;  

128.    

129.      // 省略 get/setter  

130.    

131.      @Override  

132.      public String toString() {  

133.          return "car:" + car + "\n" + "office:" + office;  

134.      }  

135.  }  

136.     

137.    

138.    

139.  我們在 Spring 容器中將 Office  Car 聲明爲 Bean,並注入到 Boss Bean 中:下面是使用傳統 XML 完成這個工作的配置文件 beans.xml  

140.    

141.    

142.  清單 4. beans.xml 將以上三個類配置成 Bean  

143.                    

144.  <?xml version="1.0" encoding="UTF-8" ?>  

145.  <beans xmlns="http://www.springframework.org/schema/beans"  

146.      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

147.      xsi:schemaLocation="http://www.springframework.org/schema/beans   

148.   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  

149.      <bean id="boss" class="com.baobaotao.Boss">  

150.          <property name="car" ref="car"/>  

151.          <property name="office" ref="office" />  

152.      </bean>  

153.      <bean id="office" class="com.baobaotao.Office">  

154.          <property name="officeNo" value="002"/>  

155.      </bean>  

156.      <bean id="car" class="com.baobaotao.Car" scope="singleton">  

157.          <property name="brand" value=紅旗 CA72"/>  

158.          <property name="price" value="2000"/>  

159.      </bean>  

160.  </beans>  

161.     

162.    

163.    

164.  當我們運行以下代碼時,控制檯將正確打出 boss 的信息:  

165.    

166.    

167.  清單 5測試類:AnnoIoCTest.java  

168.                    

169.  import org.springframework.context.ApplicationContext;  

170.  import org.springframework.context.support.ClassPathXmlApplicationContext;  

171.  public class AnnoIoCTest {  

172.    

173.      public static void main(String[] args) {  

174.          String[] locations = {"beans.xml"};  

175.          ApplicationContext ctx =   

176.              new ClassPathXmlApplicationContext(locations);  

177.          Boss boss = (Boss) ctx.getBean("boss");  

178.          System.out.println(boss);  

179.      }  

180.  }  

181.     

182.    

183.    

184.  這說明 Spring 容器已經正確完成了 Bean 創建和裝配的工作。  

185.   

186.    

187.  使用 @Autowired 註釋  

188.    

189.  Spring 2.5 引入了 @Autowired 註釋,它可以對類成員變量、方法及構造函數進行標註,完成自動裝配的工作。來看一下使用 @Autowired 進行成員變量自動注入的代碼:  

190.    

191.    

192.  清單 6使用 @Autowired 註釋的 Boss.java  

193.                    

194.  package com.baobaotao;  

195.  import org.springframework.beans.factory.annotation.Autowired;  

196.    

197.  public class Boss {  

198.    

199.      @Autowired  

200.      private Car car;  

201.    

202.      @Autowired  

203.      private Office office;  

204.    

205.      …  

206.  }  

207.     

208.    

209.    

210.  Spring 通過一個 BeanPostProcessor  @Autowired 進行解析,所以要讓 @Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean  

211.    

212.    

213.  清單 7 @Autowired 註釋工作起來  

214.                    

215.  <?xml version="1.0" encoding="UTF-8" ?>  

216.  <beans xmlns="http://www.springframework.org/schema/beans"  

217.      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

218.      xsi:schemaLocation="http://www.springframework.org/schema/beans   

219.   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  

220.    

221.      <!--  BeanPostProcessor 將自動起作用,對標註 @Autowired  Bean 進行自動注入 -->  

222.      <bean class="org.springframework.beans.factory.annotation.  

223.          AutowiredAnnotationBeanPostProcessor"/>  

224.    

225.      <!-- 移除 boss Bean 的屬性注入配置的信息 -->  

226.      <bean id="boss" class="com.baobaotao.Boss"/>  

227.     

228.      <bean id="office" class="com.baobaotao.Office">  

229.          <property name="officeNo" value="001"/>  

230.      </bean>  

231.      <bean id="car" class="com.baobaotao.Car" scope="singleton">  

232.          <property name="brand" value=紅旗 CA72"/>  

233.          <property name="price" value="2000"/>  

234.      </bean>  

235.  </beans>  

236.     

237.    

238.    

239.  這樣,當 Spring 容器啓動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有 @Autowired 註釋時就找到和其匹配(默認按類型匹配)的 Bean,並注入到對應的地方中去。  

240.    

241.  按照上面的配置,Spring 將直接採用 Java 反射機制對 Boss 中的 car  office 這兩個私有成員變量進行自動注入。所以對成員變量使用 @Autowired 後,您大可將它們的 setter 方法(setCar()  setOffice())從 Boss 中刪除。  

242.    

243.  當然,您也可以通過 @Autowired 對方法或構造函數進行標註,來看下面的代碼:  

244.    

245.    

246.  清單 8 @Autowired 註釋標註在 Setter 方法上  

247.                    

248.  package com.baobaotao;  

249.    

250.  public class Boss {  

251.      private Car car;  

252.      private Office office;  

253.    

254.       @Autowired  

255.      public void setCar(Car car) {  

256.          this.car = car;  

257.      }  

258.     

259.      @Autowired  

260.      public void setOffice(Office office) {  

261.          this.office = office;  

262.      }  

263.      …  

264.  }  

265.     

266.    

267.    

268.  這時,@Autowired 將查找被標註的方法的入參類型的 Bean,並調用方法自動注入這些 Bean。而下面的使用方法則對構造函數進行標註:  

269.    

270.    

271.  清單 9 @Autowired 註釋標註在構造函數上  

272.                    

273.  package com.baobaotao;  

274.    

275.  public class Boss {  

276.      private Car car;  

277.      private Office office;  

278.     

279.      @Autowired  

280.      public Boss(Car car ,Office office){  

281.          this.car = car;  

282.          this.office = office ;  

283.      }  

284.     

285.      …  

286.  }  

287.     

288.    

289.    

290.  由於 Boss() 構造函數有兩個入參,分別是 car  office@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作爲 Boss(Car car ,Office office) 的入參來創建 Boss Bean  

291.    

292.     

293.  當候選 Bean 數目不爲 1 時的應對方法  

294.    

295.  在默認情況下使用 @Autowired 註釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個。當找不到一個匹配的 Bean 時,Spring 容器將拋出 BeanCreationException 異常,並指出必須至少擁有一個匹配的 Bean。我們可以來做一個實驗:  

296.    

297.    

298.  清單 10候選 Bean 數目爲 0   

299.                    

300.  <?xml version="1.0" encoding="UTF-8" ?>  

301.  <beans xmlns="http://www.springframework.org/schema/beans"  

302.      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

303.       xsi:schemaLocation="http://www.springframework.org/schema/beans   

304.   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd ">  

305.     

306.      <bean class="org.springframework.beans.factory.annotation.  

307.          AutowiredAnnotationBeanPostProcessor"/>   

308.    

309.      <bean id="boss" class="com.baobaotao.Boss"/>  

310.    

311.      <!--  office Bean 註釋掉 -->  

312.      <!-- <bean id="office" class="com.baobaotao.Office">  

313.      <property name="officeNo" value="001"/>  

314.      </bean>-->  

315.    

316.      <bean id="car" class="com.baobaotao.Car" scope="singleton">  

317.          <property name="brand" value=紅旗 CA72"/>  

318.          <property name="price" value="2000"/>  

319.      </bean>  

320.  </beans>  

321.     

322.    

323.    

324.  由於 office Bean 被註釋掉了,所以 Spring 容器中將沒有類型爲 Office  Bean 了,而 Boss  office 屬性標註了 @Autowired,當啓動 Spring 容器時,異常就產生了。  

325.    

326.  當不能確定 Spring 容器中一定擁有某個類的 Bean 時,可以在需要自動注入該類 Bean 的地方可以使用 @Autowired(required = false),這等於告訴 Spring:在找不到匹配 Bean 時也不報錯。來看一下具體的例子:  

327.    

328.    

329.  清單 11使用 @Autowired(required = false)  

330.                    

331.  package com.baobaotao;  

332.    

333.  import org.springframework.beans.factory.annotation.Autowired;  

334.  import org.springframework.beans.factory.annotation.Required;  

335.    

336.  public class Boss {  

337.    

338.      private Car car;  

339.      private Office office;  

340.    

341.      @Autowired  

342.      public void setCar(Car car) {  

343.          this.car = car;  

344.      }  

345.      @Autowired(required = false)  

346.      public void setOffice(Office office) {  

347.          this.office = office;  

348.      }  

349.      …  

350.  }  

351.     

352.    

353.    

354.  當然,一般情況下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自動注入而又允許不注入的情況一般僅會在開發期或測試期碰到(如爲了快速啓動 Spring 容器,僅引入一些模塊的 Spring 配置文件),所以 @Autowired(required = false會很少用到。  

355.    

356.  和找不到一個類型匹配 Bean 相反的一個錯誤是:如果 Spring 容器中擁有多個候選 BeanSpring 容器在啓動時也會拋出 BeanCreationException 異常。來看下面的例子:  

357.    

358.    

359.  清單 12 beans.xml 中配置兩個 Office 類型的 Bean  

360.                    

361.  …   

362.  <bean id="office" class="com.baobaotao.Office">  

363.      <property name="officeNo" value="001"/>  

364.  </bean>  

365.  <bean id="office2" class="com.baobaotao.Office">  

366.      <property name="officeNo" value="001"/>  

367.  </bean>  

368.  …  

369.     

370.    

371.    

372.  我們在 Spring 容器中配置了兩個類型爲 Office 類型的 Bean,當對 Boss  office 成員變量進行自動注入時,Spring 容器將無法確定到底要用哪一個 Bean,因此異常發生了。  

373.    

374.  Spring 允許我們通過 @Qualifier 註釋指定注入 Bean 的名稱,這樣歧義就消除了,可以通過下面的方法解決異常:  

375.    

376.    

377.  清單 13使用 @Qualifier 註釋指定注入 Bean 的名稱  

378.                    

379.  @Autowired  

380.  public void setOffice(@Qualifier("office")Office office) {  

381.      this.office = office;  

382.  }  

383.     

384.    

385.    

386.  @Qualifier("office"中的 office  Bean 的名稱,所以 @Autowired  @Qualifier 結合使用時,自動注入的策略就從 byType 轉變成 byName 了。@Autowired 可以對成員變量、方法以及構造函數進行註釋,而 @Qualifier 的標註對象是成員變量、方法入參、構造函數入參。正是由於註釋對象的不同,所以 Spring 不將 @Autowired  @Qualifier 統一成一個註釋類。下面是對成員變量和構造函數入參進行註釋的代碼:  

387.    

388.  對成員變量進行註釋:  

389.    

390.    

391.  清單 14對成員變量使用 @Qualifier 註釋  

392.                    

393.  public class Boss {  

394.      @Autowired  

395.      private Car car;  

396.     

397.      @Autowired  

398.      @Qualifier("office")  

399.      private Office office;  

400.      …  

401.  }  

402.     

403.    

404.    

405.  對構造函數入參進行註釋:  

406.    

407.    

408.  清單 15對構造函數變量使用 @Qualifier 註釋  

409.                    

410.  public class Boss {  

411.      private Car car;  

412.      private Office office;  

413.    

414.      @Autowired  

415.      public Boss(Car car , @Qualifier("office")Office office){  

416.          this.car = car;  

417.          this.office = office ;  

418.      }  

419.  }  

420.     

421.    

422.    

423.  @Qualifier 只能和 @Autowired 結合使用,是對 @Autowired 有益的補充。一般來講,@Qualifier 對方法簽名中入參進行註釋會降低代碼的可讀性,而對成員變量註釋則相對好一些。  

424.    

425.   

426.    

427.  使用 JSR-250 的註釋  

428.    

429.  Spring 不但支持自己定義的 @Autowired 的註釋,還支持幾個由 JSR-250 規範定義的註釋,它們分別是 @Resource@PostConstruct 以及 @PreDestroy  

430.    

431.  @Resource  

432.    

433.  @Resource 的作用相當於 @Autowired,只不過 @Autowired  byType 自動注入,面 @Resource 默認按 byName 自動注入罷了。@Resource 有兩個屬性是比較重要的,分別是 name  typeSpring  @Resource 註釋的 name 屬性解析爲 Bean 的名字,而 type 屬性則解析爲 Bean 的類型。所以如果使用 name 屬性,則使用 byName 的自動注入策略,而使用 type 屬性時則使用 byType 自動注入策略。如果既不指定 name 也不指定 type 屬性,這時將通過反射機制使用 byName 自動注入策略。  

434.    

435.  Resource 註釋類位於 Spring 發佈包的 lib/j2ee/common-annotations.jar 類包中,因此在使用之前必須將其加入到項目的類庫中。來看一個使用 @Resource 的例子:  

436.    

437.    

438.  清單 16使用 @Resource 註釋的 Boss.java  

439.                    

440.  package com.baobaotao;  

441.    

442.  import javax.annotation.Resource;  

443.    

444.  public class Boss {  

445.      // 自動注入類型爲 Car  Bean  

446.      @Resource  

447.      private Car car;  

448.    

449.      // 自動注入 bean 名稱爲 office  Bean  

450.      @Resource(name = "office")  

451.      private Office office;  

452.  }  

453.     

454.    

455.    

456.  一般情況下,我們無需使用類似於 @Resource(type=Car.class的註釋方式,因爲 Bean 的類型信息可以通過 Java 反射從代碼中獲取。  

457.    

458.  要讓 JSR-250 的註釋生效,除了在 Bean 類中標註這些註釋外,還需要在 Spring 容器中註冊一個負責處理這些註釋的 BeanPostProcessor  

459.    

460.  <bean   

461.    class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>  

462.     

463.    

464.    

465.  CommonAnnotationBeanPostProcessor 實現了 BeanPostProcessor 接口,它負責掃描使用了 JSR-250 註釋的 Bean,並對它們進行相應的操作。  

466.    

467.  @PostConstruct  @PreDestroy  

468.    

469.  Spring 容器中的 Bean 是有生命週期的,Spring 允許在 Bean 在初始化完成後以及 Bean 銷燬前執行特定的操作,您既可以通過實現 InitializingBean/DisposableBean 接口來定製初始化之後 / 銷燬之前的操作方法,也可以通過 <bean> 元素的 init-method/destroy-method 屬性指定初始化之後 / 銷燬之前調用的操作方法。關於 Spring 的生命週期,筆者在《精通 Spring 2.x—企業應用開發精解》第 3 章進行了詳細的描述,有興趣的讀者可以查閱。  

470.    

471.  JSR-250 爲初始化之後/銷燬之前方法的指定定義了兩個註釋類,分別是 @PostConstruct  @PreDestroy,這兩個註釋只能應用於方法上。標註了 @PostConstruct 註釋的方法將在類實例化後調用,而標註了 @PreDestroy 的方法將在類銷燬之前調用。  

472.    

473.    

474.  清單 17使用 @PostConstruct  @PreDestroy 註釋的 Boss.java  

475.                    

476.  package com.baobaotao;  

477.    

478.  import javax.annotation.Resource;  

479.  import javax.annotation.PostConstruct;  

480.  import javax.annotation.PreDestroy;  

481.    

482.  public class Boss {  

483.      @Resource  

484.      private Car car;  

485.    

486.      @Resource(name = "office")  

487.      private Office office;  

488.    

489.      @PostConstruct  

490.      public void postConstruct1(){  

491.          System.out.println("postConstruct1");  

492.      }  

493.    

494.      @PreDestroy  

495.      public void preDestroy1(){  

496.          System.out.println("preDestroy1");   

497.      }  

498.      …  

499.  }  

500.     

501.    

502.    

503.  您只需要在方法前標註 @PostConstruct  @PreDestroy,這些方法就會在 Bean 初始化後或銷燬之前被 Spring 容器執行了。  

504.    

505.  我們知道,不管是通過實現 InitializingBean/DisposableBean 接口,還是通過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能爲 Bean 指定一個初始化 / 銷燬的方法。但是使用 @PostConstruct  @PreDestroy 註釋卻可以指定多個初始化 / 銷燬方法,那些被標註 @PostConstruct  @PreDestroy 註釋的方法都會在初始化 / 銷燬時被執行。  

506.    

507.  通過以下的測試代碼,您將可以看到 Bean 的初始化 / 銷燬方法是如何被執行的:  

508.    

509.    

510.  清單 18測試類代碼  

511.                    

512.  package com.baobaotao;  

513.    

514.  import org.springframework.context.support.ClassPathXmlApplicationContext;  

515.    

516.  public class AnnoIoCTest {  

517.    

518.      public static void main(String[] args) {  

519.          String[] locations = {"beans.xml"};  

520.          ClassPathXmlApplicationContext ctx =   

521.              new ClassPathXmlApplicationContext(locations);  

522.          Boss boss = (Boss) ctx.getBean("boss");  

523.          System.out.println(boss);  

524.          ctx.destroy();// 關閉 Spring 容器,以觸發 Bean 銷燬方法的執行  

525.      }  

526.  }  

527.     

528.    

529.    

530.  這時,您將看到標註了 @PostConstruct  postConstruct1() 方法將在 Spring 容器啓動時,創建 Boss Bean 的時候被觸發執行,而標註了 @PreDestroy 註釋的 preDestroy1() 方法將在 Spring 容器關閉前銷燬 Boss Bean 的時候被觸發執行。  

531.    

532.    

533.  使用 <context:annotation-config/> 簡化配置  

534.    

535.  Spring 2.1 添加了一個新的 context  Schema 命名空間,該命名空間對註釋驅動、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道註釋本身是不會做任何事情的,它僅提供元數據信息。要使元數據信息真正起作用,必須讓負責處理這些元數據的處理器工作起來。   

536.    

537.  而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor  CommonAnnotationBeanPostProcessor 就是處理這些註釋元數據的處理器。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 爲我們提供了一種方便的註冊這些 BeanPostProcessor 的方式,這就是 <context:annotation-config/>。請看下面的配置:  

538.    

539.    

540.  清單 19調整 beans.xml 配置文件  

541.                    

542.  <?xml version="1.0" encoding="UTF-8" ?>  

543.  <beans xmlns="http://www.springframework.org/schema/beans"  

544.      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

545.       xmlns:context="http://www.springframework.org/schema/context"  

546.       xsi:schemaLocation="http://www.springframework.org/schema/beans   

547.   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  

548.   http://www.springframework.org/schema/context   

549.   http://www.springframework.org/schema/context/spring-context-2.5.xsd">  

550.     

551.      <context:annotation-config/>   

552.    

553.      <bean id="boss" class="com.baobaotao.Boss"/>  

554.      <bean id="office" class="com.baobaotao.Office">  

555.          <property name="officeNo" value="001"/>  

556.      </bean>  

557.      <bean id="car" class="com.baobaotao.Car" scope="singleton">  

558.          <property name="brand" value=紅旗 CA72"/>  

559.          <property name="price" value="2000"/>  

560.      </bean>  

561.  </beans>  

562.     

563.    

564.    

565.  <context:annotationconfig/> 將隱式地向 Spring 容器註冊 AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor  4  BeanPostProcessor  

566.    

567.  在配置文件中使用 context 命名空間之前,必須在 <beans> 元素中聲明 context 命名空間。  

568.    

569.   

570.  使用 @Component  

571.    

572.  雖然我們可以通過 @Autowired  @Resource  Bean 類中使用自動注入功能,但是 Bean 還是在 XML 文件中通過 <bean> 進行定義 —— 也就是說,在 XML 配置文件中定義 Bean,通過 @Autowired  @Resource  Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。能否也通過註釋定義 Bean,從 XML 配置文件中完全移除 Bean 定義的配置呢?答案是肯定的,我們通過 Spring 2.5 提供的 @Component 註釋就可以達到這個目標了。  

573.    

574.  下面,我們完全使用註釋定義 Bean 並完成 Bean 之間裝配:  

575.    

576.    

577.  清單 20使用 @Component 註釋的 Car.java  

578.                    

579.  package com.baobaotao;  

580.    

581.  import org.springframework.stereotype.Component;  

582.    

583.  @Component  

584.  public class Car {  

585.      …  

586.  }  

587.     

588.    

589.    

590.  僅需要在類定義處,使用 @Component 註釋就可以將一個類定義了 Spring 容器中的 Bean。下面的代碼將 Office 定義爲一個 Bean  

591.    

592.    

593.  清單 21使用 @Component 註釋的 Office.java  

594.                    

595.  package com.baobaotao;  

596.    

597.  import org.springframework.stereotype.Component;  

598.    

599.  @Component  

600.  public class Office {  

601.      private String officeNo = "001";  

602.      …  

603.  }  

604.     

605.    

606.    

607.  這樣,我們就可以在 Boss 類中通過 @Autowired 注入前面定義的 Car  Office Bean 了。  

608.    

609.    

610.  清單 22使用 @Component 註釋的 Boss.java  

611.                    

612.  package com.baobaotao;  

613.    

614.  import org.springframework.beans.factory.annotation.Autowired;  

615.  import org.springframework.beans.factory.annotation.Required;  

616.  import org.springframework.beans.factory.annotation.Qualifier;  

617.  import org.springframework.stereotype.Component;  

618.    

619.  @Component("boss")  

620.  public class Boss {  

621.      @Autowired  

622.      private Car car;  

623.    

624.      @Autowired  

625.      private Office office;  

626.      …  

627.  }  

628.     

629.    

630.    

631.  @Component 有一個可選的入參,用於指定 Bean 的名稱,在 Boss 中,我們就將 Bean 名稱定義爲“boss”。一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過 byType 策略就可以自動注入了,所以大可不必指定 Bean 的名稱。  

632.    

633.  在使用 @Component 註釋後,Spring 容器必須啓用類掃描機制以啓用註釋驅動 Bean 定義和註釋驅動 Bean 自動注入的策略。Spring 2.5  context 命名空間進行了擴展,提供了這一功能,請看下面的配置:  

634.    

635.    

636.  清單 23簡化版的 beans.xml  

637.                    

638.  <?xml version="1.0" encoding="UTF-8" ?>  

639.  <beans xmlns="http://www.springframework.org/schema/beans"  

640.      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

641.      xmlns:context="http://www.springframework.org/schema/context"  

642.      xsi:schemaLocation="http://www.springframework.org/schema/beans   

643.   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  

644.   http://www.springframework.org/schema/context   

645.   http://www.springframework.org/schema/context/spring-context-2.5.xsd">  

646.      <context:component-scan base-package="com.baobaotao"/>  

647.  </beans>  

648.     

649.    

650.    

651.  這裏,所有通過 <bean> 元素定義 Bean 的配置內容已經被移除,僅需要添加一行 <context:component-scan/> 配置就解決所有問題了——Spring XML 配置文件得到了極致的簡化(當然配置元數據還是需要的,只不過以註釋形式存在罷了)。<context:component-scan/>  base-package 屬性指定了需要掃描的類包,類包及其遞歸子包中所有的類都會被處理。  

652.    

653.  <context:component-scan/> 還允許定義過濾器將基包下的某些類納入或排除。Spring 支持以下 4 種類型的過濾方式,通過下表說明:  

654.    

655.    

656.   1掃描過濾方式  

657.  過濾器類型 說明   

658.  註釋 假如 com.baobaotao.SomeAnnotation 是一個註釋類,我們可以將使用該註釋的類過濾出來。   

659.  類名指定 通過全限定類名進行過濾,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外。   

660.  正則表達式 通過正則表達式定義過濾的類,如下所示: com\.baobaotao\.Default.*   

661.  AspectJ 表達式 通過 AspectJ 表達式定義過濾的類,如下所示: com. baobaotao..*Service+   

662.    

663.  下面是一個簡單的例子:  

664.    

665.  <context:component-scan base-package="com.baobaotao">  

666.      <context:include-filter type="regex"   

667.          expression="com\.baobaotao\.service\..*"/>  

668.      <context:exclude-filter type="aspectj"   

669.          expression="com.baobaotao.util..*"/>  

670.  </context:component-scan>  

671.     

672.    

673.    

674.  值得注意的是 <context:component-scan/> 配置項不但啓用了對類包進行掃描以實施註釋驅動 Bean 定義的功能,同時還啓用了註釋驅動自動注入的功能(即還隱式地在內部註冊了 AutowiredAnnotationBeanPostProcessor  CommonAnnotationBeanPostProcessor),因此當使用 <context:component-scan/> 後,就可以將 <context:annotation-config/> 移除了。  

675.    

676.  默認情況下通過 @Component 定義的 Bean 都是 singleton 的,如果需要使用其它作用範圍的 Bean,可以通過 @Scope 註釋來達到目標,如以下代碼所示:  

677.    

678.    

679.  清單 24通過 @Scope 指定 Bean 的作用範圍  

680.                    

681.  package com.baobaotao;  

682.  import org.springframework.context.annotation.Scope;  

683.  …  

684.  @Scope("prototype")  

685.  @Component("boss")  

686.  public class Boss {  

687.      …  

688.  }  

689.     

690.    

691.  這樣,當從 Spring 容器中獲取 boss Bean 時,每次返回的都是新的實例了。  

692.    

693.    

694.  採用具有特殊語義的註釋  

695.    

696.  Spring 2.5 中除了提供 @Component 註釋外,還定義了幾個擁有特殊語義的註釋,它們分別是:@Repository@Service  @Controller。在目前的 Spring 版本中,這 3 個註釋和 @Component 是等效的,但是從註釋類的命名上,很容易看出這 3 個註釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個註釋和 @Component 相比沒有什麼新意,但 Spring 將在以後的版本中爲它們添加特殊的功能。所以,如果 Web 應用程序採用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別採用 @Repository@Service  @Controller 對分層中的類進行註釋,而用 @Component 對那些比較中立的類進行註釋。  

697.    

698.    

699.    

700.  註釋配置和 XML 配置的適用場合  

701.    

702.  是否有了這些 IOC 註釋,我們就可以完全摒除原來 XML 配置的方式呢?答案是否定的。有以下幾點原因:  

703.    

704.  註釋配置不一定在先天上優於 XML 配置。如果 Bean 的依賴關係是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發生調整,那麼註釋配置優於 XML 配置;反之如果這種依賴關係會在部署時發生調整,XML 配置顯然又優於註釋配置,因爲註釋是對 Java 源代碼的調整,您需要重新改寫源代碼並重新編譯纔可以實施調整。   

705.  如果 Bean 不是自己編寫的類(如 JdbcTemplateSessionFactoryBean 等),註釋配置將無法實施,此時 XML 配置是唯一可用的方式。   

706.  註釋配置往往是類級別的,而 XML 配置則可以表現得更加靈活。比如相比於 @Transaction 事務註釋,使用 aop/tx 命名空間的事務配置更加靈活和簡單。   

707.  所以在實現應用中,我們往往需要同時使用註釋配置和 XML 配置,對於類級別且不會發生變動的配置可以優先考慮註釋配置;而對於那些第三方類以及容易發生調整的配置則應優先考慮使用 XML 配置。Spring 會在具體實施 Bean 創建和 Bean 注入之前將這兩種配置方式的元信息融合在一起。  

708.    

709.     

710.  小結  

711.    

712.  Spring  2.1 以後對註釋配置提供了強力的支持,註釋配置功能成爲 Spring 2.5 的最大的亮點之一。合理地使用 Spring 2.5 的註釋配置,可以有效減少配置的工作量,提高程序的內聚性。但是這並不意味着傳統 XML 配置將走向消亡,在第三方類 Bean 的配置,以及那些諸如數據源、緩存池、持久層操作模板類、事務管理等內容的配置上,XML 配置依然擁有不可替代的地位。  

 


發佈了35 篇原創文章 · 獲贊 5 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章