@Autowired和@Resource都可以用於來實現依賴注入,但前者是Spring提供的,後者為JDK(JSR-250標準)自帶的。阿里Java開發規範中推薦使用@Resource。但大多數人往往並沒有留意為何如此,甚至程式碼中的提示資訊可能都沒留意去看。
本文就帶大家徹底瞭解一下這兩個註解的功能、運用場景及區別。
IDE的提示如果在專案中使用@Autowired進行注入,如下程式碼:
@RestControllerpublic class InjectController { @Autowired private ConnectService connectService;}
會有這樣的提示資訊:
Field injection is not recommended Inspection info: Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".
翻譯過來就是:欄位注入是不推薦的,Spring團隊建議:“始終在bean中使用基於建構函式的依賴項注入。始終對強制性依賴項使用斷言”。
根據提示,我們來重新寫一種注入方式:
@RestControllerpublic class InjectController { private ConnectService connectService; @Autowired public void setConnectService(ConnectService connectService) { this.connectService = connectService; }}
上面將@Autowired的註解使用在了setter方法上,此時提示消失了。再看另外一種注入方式:
@RestControllerpublic class InjectController { private ConnectService connectService; @Autowired public InjectController(ConnectService connectService) { this.connectService = connectService; }}
此種方式將@Autowired的註解使用在了構造方法上,與Spring團隊的建議一致。此時,也不會再出現警告資訊。
也就是說IDE提示的資訊並不是說不建議大家使用@Autowired註解,而且不要直接使用在欄位(Field)上。
Spring注入的方式及場景Spring常見的DI方式:構造器注入、Setter注入、欄位注入。顯然,我們經常使用的方式並不是官方最推薦的。
而上面三種注入方式所適用的場景也是有所區別的:1、構造器注入適用具有強依賴和不變性的依賴;2、Setter注入適用於具有可選性和可變性的依賴注入;3、Field注入,儘量少使用,如果需要則使用@Resource進行替代,以降低耦合性。
Field注入的缺點Field注入的缺點很明顯,比如不能像構造器注入那樣注入不可變的物件,依賴對外部不可見(構造器和Setter可見,而private的屬性不可見),會導致元件與IoC容器(比如Spring)緊密耦合,單元測試也需要使用IoC容器,依賴過多時相對構造器注入不能夠明顯的看出依賴過多(違反單一職責原則)。
既然Field注入這麼多缺點,但為什麼大家還是習慣使用呢?主要原因:太方便了,極大的縮減了程式碼。而且大多數業務並不需要用構造器強繫結,同時換IoC容器的可能性也極低。所以,雖然官方及IDE一直強調和提醒,但貌似並沒有阻止程式設計師的使用。
為什麼只對@Autowired警告最主要的原因是:@Autowired是Spring提供的,是特定IoC提供的特定註解,與框架形成了強繫結,一旦換用其他IoC框架,是無法支援注入的。而@Resource是JSR-250提供的,IoC容器應當去相容它,即使更換容器,也可以正常工作。
另外可能還跟這兩種註解的工作機制有關。預設情況下@Autowired是以型別(ByType)進行匹配的,@Resource是以名字(ByName)進行匹配的。也就是說當容器中存在兩個相同型別的Bean時,使用@Autowired注入會報錯,而使用@Resource會更精準。當然@Autowired也可以指定名稱(還需配合@Qualifier註解)。
@Autowired和@Resource功能就Spring而言,不但支援自定義的@Autowired註解,還支援幾個由JSR-250規範定義的註解,分別為@Resource、@PostConstruct以及@PreDestroy。
而@Autowired和@Resource的功能基本一致,@Resource的作用相當於@Autowired,只不過@Autowired預設按byType自動注入,而@Resource預設按byName自動注入。
@Resource有兩個核心屬性:name和type。Spring將@Resource註解的name屬性解析為bean的名字,type屬性則解析為bean的型別。預設情況下會透過反射機制使用byName自動注入策略。
@Resource裝配場景:
1、如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則丟擲異常;2、如果指定了name,則根據名稱進行裝配,找不到則丟擲異常;3、如果指定了type,則根據型別進行裝配,找不到或者找到多個,都會丟擲異常;4、沒有任何指定(預設情況),則採用byName方式進行裝配,如果沒有匹配到,則回退為一個原始型別進行匹配;小結處於對程式碼的潔癖,不習慣@Autowired的提示資訊,於是整個專案中都強力推薦使用@Resource註解。瞭解了這一提示的底層原理,或許你就可以選擇最適合自己的注入形式了。