JavaConfig方式以及處理自動裝配歧義性-spring基礎學習
在XML配置和直接註解式配置之外還有一種有趣的選擇方式-JavaConfig,java config是指基於java配置的spring。傳統的Spring一般都是基本xml配置的,後來spring3.0新增了許多java config的註解,特別是spring boot,基本都是清一色的java config。下面用一段簡單的程式來演示.
- 使用IDEA建立一個Maven專案
- 在pom.xml 中引用依賴
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.13.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.13.RELEASE</version> </dependency>
專案結構圖
- 程式碼說明和實現
Dao層和Service層不贅述了,簡單實現一個add()方法
完整程式碼已上傳github: GitHub
AppConfig配置類
用@Configuration註解該類,等價 與XML中配置beans;用@Bean標註方法等價於XML中配置bean,被註解的類內部包含有一個或多個被@Bean註解的方法
UserDaoNormal
@Configuration public class AppConfig { @Bean public UserDao userDaoNormal(){ System.out.println("建立UserDaoNormal物件"); return new UserDaoNormal(); @Bean public UserDao userDaoCache() { System.out.println("建立UserDaoCache物件"); return new UserDaoCache(); } @Bean public UserService userServiceNormal(UserDao userDao){ System.out.println("建立一個UserService物件"); return new UserServiceNormal(userDao); } }
UserServiceTest測試類
@RunWith(SpringJUnit4ClassRunner.class),讓測試運行於Spring測試環境
@ContextConfiguration Spring整合JUnit4測試時,使用註解引入多個配置檔案
多個配置檔案:@ContextConfiguration(locations = { "classpath :/spring1.xml", "classpath :/spring2.xml" })
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = AppConfig.class) public class UserServiceTest { @Autowired private UserService userService; @Test public void addTest(){ userService.add(); } }
執行後卻報異常出錯!
問題是出現了依賴注入的歧義性,UserDao不能夠進行自動裝配.簡單來說,在spring容器中找到了一個以上的UserDao型別的物件,所以不知道到底要哪個,我在UserDao介面寫了兩個實現add()方法的類,有一個UserDaoNormal物件和一個UserDaoCache物件,所以無法正常進行依賴注入.
解決的辦法有幾個:
1.@primary註解
在AppConfig配置檔案里根據需要在兩個物件方法上在其中一個新增 @primary註解,說明這個物件是依賴注入的首選bean.
2.@Qualifier註解
Qualifier的意思是合格者,通過這個標示,表明了哪個實現類才是我們所需要的,新增@Qualifier註解,需要注意的是@Qualifier的引數名稱為我們之前定義@Qualifier註解的名稱之一。
程式碼如下
@Configuration public class AppConfig { @Bean @Qualifier("normal") public UserDao userDaoNormal(){ System.out.println("建立UserDaoNormal物件"); return new UserDaoNormal(); } @Bean @Qualifier("cache") public UserDao userDaoCache() { System.out.println("建立UserDaoCache物件"); return new UserDaoCache(); } @Bean public UserService userServiceNormal(@Qualifier("normal") UserDao userDao){ System.out.println("建立一個UserService物件"); return new UserServiceNormal(userDao); } }
3.@Qualifier註解和bean id
同樣的,@Qualifier的引數名稱為我們之前定義@bean註解的名稱之一。
程式碼如下:
@Bean("normal") public UserDao userDaoNormal(){ System.out.println("建立UserDaoNormal物件"); return new UserDaoNormal(); } @Bean("cache") public UserDao userDaoCache() { System.out.println("建立UserDaoCache物件"); return new UserDaoCache(); } @Bean public UserService userServiceNormal(@Qualifier("normal") UserDao userDao){ System.out.println("建立一個UserService物件"); return new UserServiceNormal(userDao);
如果我們不給bean起一個約定的id,會有一個預設的id,實際上就是@bean所在的方法的方法名.@Qualifier的引數名稱為@bean所在的方法的方法名的名稱之一。
程式碼如下:
@Bean public UserDao userDaoNormal(){ System.out.println("建立UserDaoNormal物件"); return new UserDaoNormal(); } @Bean public UserDao userDaoCache() { System.out.println("建立UserDaoCache物件"); return new UserDaoCache(); } @Bean public UserService userServiceNormal(@Qualifier("userDaoCache") UserDao userDao){ System.out.println("建立一個UserService物件"); return new UserServiceNormal(userDao); }
4.執行後的兩種結果