文章目錄
- 一、什么是DI
- 二、注入的三種方式
- 2.1 屬性注入 @Autowired
- 使用方法
- @Autowired存在的問題以及解決方法
- @Autowired問題的解決方法
- 2.2 構造方法注入
- 2.3 setter方法注入
- 2.4 三種注入方式優缺點分析
一、什么是DI
- 概念:DI(依賴注入)就是當我們把依賴對象取出來(創建好后),賦值給該對象的屬性
- DI的其他翻譯:屬性裝配、依賴裝配
二、注入的三種方式
注入只是去拿,但是有沒有,是要依靠【Spring實現的loC的方式】
2.1 屬性注入 @Autowired
使用方法
- @Autowired 作用:告訴Spring我們需要這個對象,去loC容器里拿
- @Autowired 注入原則
- 在注入時,是根據類型去注入的
- 如果一個類型存在多個對象時,優先名稱匹配,如果名稱都匹配不上,就會報錯。
@Controller
public class TestController {@Autowiredprivate UserService userService;public void doController(){userService.doService();System.out.println("這是Controoler注解");}
}@Service
public class UserService {public void doService(){System.out.println("這是Service注解");}
}
- 關于報錯:因為@Autowired不是官方推薦寫法,所以IDEA可能會報錯。但即便如此,由于操作簡單,使用量依舊很高
- 使用Debug查看當前變量的值:Debug狀態下,選中某個變量,選擇“Evaluate Expression……”可以進行數值模擬
@Autowired存在的問題以及解決方法
因為構造方法注入和Setter注入都是依據@Autowired實現的,所以它們也存在下面的問題
- 有多個類型時要根據名稱去拿,有報錯的風險
- 沒有辦法去注入一個由final修飾的屬性:因為final是不可變的,要求是在定義期間或初始化期間給其賦值
- 使用量太高了,可能會濫用
- 違反了軟件設計的單一原則
@Autowired問題的解決方法
【1】方法介紹:
-
讓屬性名和你需要的對象名稱一致:這樣@Autowired就可以根據名稱匹配
-
如果不想保持一致:使用@Primary、@Qualifier
- @Primary:標識默認的對象
- @Qualifier:指定要使用的Bean名稱
- 既然@Autowired沒辦法加上屬性名,我們就用其他的注解來給其加上屬性名
- @Resource:通過描述bean的信息,去指定要用哪個
-
重命名Bean:
-
@Autowird VS @Resource
- 提供者不同:ctrl或選中注解就可以出現該注解的相關信息,點擊小圓球可以定位包。rt是jdk的包。
- @Autowired 是Spring框架提供的注解,而@Resource是JDK提供的注解
- 注入方式:
- @Autowired 默認是按照類型注入,如果同一個類型存在多個,再按照名稱匹配,如果名稱匹配不上,就會報錯
- @Resource 支持更多的參數設置,例如 name 設置,可以根據名稱獲取 Bean
- 提供者不同:ctrl或選中注解就可以出現該注解的相關信息,點擊小圓球可以定位包。rt是jdk的包。
【2】方法的具體使用:
- 使用@Primary:
@Configuration
public class BeanConfig {@Beanpublic UserInfo userInfoZ(){UserInfo userInfo = new UserInfo();userInfo.setUsername("zhangsan");userInfo.setPassword("123456");return userInfo;}@Primary@Beanpublic UserInfo userInfoL(){UserInfo userInfo = new UserInfo();userInfo.setUsername("lisi");userInfo.setPassword("123456");return userInfo;}}@Controller
public class TestController {@Autowiredprivate UserInfo userInfo;public void doController(){System.out.println(userInfo); //lisi}
}
- 使用@Qualifier:
@Configuration
public class BeanConfig {@Beanpublic UserInfo userInfoZ(){UserInfo userInfo = new UserInfo();userInfo.setUsername("zhangsan");userInfo.setPassword("123456");return userInfo;}@Beanpublic UserInfo userInfoL(){UserInfo userInfo = new UserInfo();userInfo.setUsername("lisi");userInfo.setPassword("123456");return userInfo;}}@Controller
public class TestController {@Qualifier("userInfoZ")@Autowiredprivate UserInfo userInfo;public void doController(){System.out.println(userInfo); //zhangsan}
}
- 使用@Resource:
@Configuration
public class BeanConfig {@Beanpublic UserInfo userInfoZ(){UserInfo userInfo = new UserInfo();userInfo.setUsername("zhangsan");userInfo.setPassword("123456");return userInfo;}@Beanpublic UserInfo userInfoW(String nameW){UserInfo userInfo = new UserInfo();userInfo.setUsername(nameW);userInfo.setPassword("123456");return userInfo;}@Beanpublic String nameW(){return "wangwu";}}@Controller
public class TestController {@Resource(name = "userInfoW")@Autowiredprivate UserInfo userInfo;public void doController(){System.out.println(userInfo); //wangwu}
}
- 重命名Bean:
@Configuration
public class BeanConfig {@Bean("u1")public UserInfo userInfoZ(){UserInfo userInfo = new UserInfo();userInfo.setUsername("zhangsan");userInfo.setPassword("123456");return userInfo;}@Beanpublic UserInfo userInfoL(){UserInfo userInfo = new UserInfo();userInfo.setUsername("lisi");userInfo.setPassword("123456");return userInfo;}}@Controller
public class TestController {@Autowiredprivate UserInfo u1;public void doController(){System.out.println(u1); //zhangsan}
}
2.2 構造方法注入
- 構造函數的創建問題:
- 當我們新增了屬性時,可能就要去新加上構造方法,十分繁瑣
- 當我們添加了有參的構造函數,就不會默認生成無參的構造函數了,如果需要用無參的,就需要手動生成
- @Autowired 指定用哪個構造函數:當有多個構造函數且沒有指定用哪個時,Spring去初始化就會不知道用哪個,可能會報錯
- 如果有無參構造函數,默認用無參的,此時userService為null
- 如果沒有無參構造函數,我們需要用@Autowired告訴Spring使用哪個構造函數。當然,如果只有一個構造函數時,@Autowired是可以省略的
@Controller
public class TestController {private UserService userService;@Autowiredpublic TestController(UserService userService) {this.userService = userService;}public TestController() {}public void doController(){userService.doService();System.out.println("這是Controoler注解");}
}@Service
public class UserService {public void doService(){System.out.println("這是Service注解");}
}
2.3 setter方法注入
@Controller
public class TestController {private UserService userService;@Autowired //需要加上,不加會報錯public void setUserService(UserService userService) {this.userService = userService;}public void doController(){userService.doService();System.out.println("這是Controoler注解");}
}
2.4 三種注入方式優缺點分析
- 屬性注入:雖然不被官方推薦,但因為簡單,程序員推薦使用
- 優點: 簡潔,使用方便
- 缺點:
- @Autowired是Spring提供的,只能在Spring這使用
- 不能注入?個Final修飾的屬性
- 構造函數注?(Spring 4.X推薦)
- 優點:
- 符合final可以在構造方法中賦值的設定,故而可以注入final修飾的屬性
- 注入的對象不會被修改。因為構造函數是在創建對象的時候執行的,執行完之后除非再創建一個對象,或者使用Setter注入,否則不會輕易被改變。
- 依賴對象在使用前?定會被完全初始化,因為依賴是在類的構造方法中執行的,而構造方法是在類加載階段就會執行的方法
- 通用性好, 構造方法是JDK支持的,即使是更換任何框架,他都是適用的
- 缺點:注入多個對象時, 代碼會比較繁瑣,還需要用@Autowired指定
- 優點:
- Setter注入(Spring 3.X推薦):事實上,當一個對象需要被修改,我們就沒必要交給Spring管理了,直接自己new一個算了
- 優點:方便在類實例之后, 重新對該對象進行配置或者注入
- 缺點:
- 不能注入?個Final修飾的屬性
- 注入對象可能會被改變, 因為setter方法可能會被多次調用, 就有被修改的風險。你能改別人也能改,代碼就會很亂。