@AUTOWIRED VS @INJECT VS @RESOURCE
我們可以使用下面三個註釋來注入依賴項。
- @Resource–在javax.annotation包中定義,此註釋是JSR-250註釋集合的一部分,與javaee一起打包。
- @Inject–在javax.inject包中定義。為了訪問@inject註釋,javax.inject庫必須宣告為Maven依賴項。
- @Autowired–在org.springframework.bean.factory包中定義,也是Spring框架的一部分。
@Autowired和@Inject註解的行為相同。這兩個註解使用AutowiredAnnotationBeanPostProcessor注入依賴關係。
@Resource使用CommonAnnotationBeanPostProcessor注入依賴項。
執行的順序
@Autowired和@Inject
- 按Type匹配
- 按Qualifiers匹配
- 按Name匹配
@Resource
- 按Name匹配
- 按Type匹配
- 按Qualifiers匹配(如果按Name找到匹配項,則忽略)
在下面的示例中,讓我們看看這些註釋是如何工作的。
這裡,我們有Animal介面和兩個實現Tiger和Lion。
Animal:
/** * @author:crelle * @className:Animal * @version:1.0.0 * @date:2020/9/23 * @description:XX **/ public interface Animal { String type(); }Tiger:
import org.springframework.stereotype.Component; /** * @author:crelle * @className:Tiger * @version:1.0.0 * @date:2020/9/23 * @description:XX **/ @Component public class Tiger implements Animal { @Override public String type() { return "Tiger"; } }
Lion:
import org.springframework.stereotype.Component;/** * @author:crelle * @className:Lion * @version:1.0.0 * @date:2020/9/23 * @description:XX **/ @Component public class Lion implements Animal { @Override public String type() { return "Lion"; } }
場景1:介面型別注入——使用@Resource或@Inject或@Autowired
AnimalKeeper1:
import org.springframework.beans.factory.annotation.Autowired; import javax.inject.Inject; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author:crelle * @className:AnimalKeeper * @version:1.0.0 * @date:2020/9/23 * @description: cenario 1 : Inject using Interface type – Using @Resource or @Inject or @Autowired **/ @Component public class AnimalKeeper1 { @Resource
private Animal animal; // @Inject // private Animal animal; // // @Autowired // private Animal animal; public Animal getAnimal() { return animal; } }
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication implements CommandLineRunner { @Autowired private AnimalKeeper1 animalKeeper; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println(animalKeeper.getAnimal().type()); } }
輸出
Field animalKeeper in crelle.test.springframework.DemoApplication required a single bean, but 2 were found: - lion: defined in file [D:\coding\try-new-technologies\spring-framework-test\target\classes\crelle\test\springframework\beans\factory\annotation\annotationtypes\test1\Lion.class] - tiger: defined in file [D:\coding\try-new-technologies\spring-framework-test\target\classes\crelle\test\springframework\beans\factory\annotation\annotationtypes\test1\Tiger.class]
使用下面的註解也會給出上面的錯誤。
@Inject private Animal animal; @Autowired private Animal animal;
所有的註解都在做同樣的事情,即嘗試按Type注入依賴項(Tiger和Lion).因此Spring容器不知道要注入Tiger或者Lion,注入失敗!
如果你確定要注入Tiger實現類,可以使用@Primary註解。
場景2:使用filed type 作為具體類進行注入:-使用@Resource或@Inject或@Autowired
AnimalKeeper2:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.Resource; import javax.inject.Inject; /** * @author:crelle * @className:AnimalKeeper1 * @version:1.0.0 * @date:2020/9/23 * @description: Scenario 2 : Inject using field type as concrete class:- Using @Resource or @Inject or @Autowired **/ @Component public class AnimalKeeper2 { // @Resource // private Tiger animal; // @Inject // private Tiger animal; @Autowired private Tiger animal; public Tiger getAnimal() { return animal; } }
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication implements CommandLineRunner { @Autowired private AnimalKeeper2 animalKeeper; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println(animalKeeper.getAnimal().type()); } }
輸出:
Tiger
所有的註解都得到了成功的注入。
原因-所有人都在嘗試按Type注入,而Animal的型別是具體的Tiger,所以注入沒有歧義。
場景3:使用filed name注入:-使用@Resource或@Inject或@Autowired
AnimalKeeper3:
import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author:crelle * @className:AnimalKeeper2 * @version:1.0.0 * @date:2020/9/23 * @description: Scenario 3 : Injecting using field name:- Using @Resource or @Inject or @Autowired **/ @Component public class AnimalKeeper3 { @Resource private Animal tiger; // @Inject // private Animal tiger; // @Autowired // private Animal tiger; public Animal getTiger() { return tiger; } }
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication implements CommandLineRunner { @Autowired private AnimalKeeper3 animalKeeper; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println(animalKeeper.getTiger().type()); } }
輸出:
Tiger
所有註解都將成功注入。
原因:它是按filed name注入的,每當我們在類上使用@Component時,類名本身就會自動註冊為spring bean。
Tiger類用Spring容器註冊為tiger bean,而tiger bean是容器中唯一可用的類,因此沒有歧義。
場景4:使用具有正確限定符名稱的Qualifier:-使用@Resource或@Inject或@Autowired
AnimalKeeper4:
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author:crelle * @className:AnimalKeeper4 * @version:1.0.0 * @date:2020/9/23 * @description: Scenario 4 : Using Qualifier with correct qualifier name:- Using @Resource or @Inject or @Autowired **/ @Component public class AnimalKeeper4 { @Resource @Qualifier("tiger") private Animal animal; // @Inject // @Qualifier(“tiger”) // private Animal animal; // @Autowired // @Qualifier(“tiger”) // private Animal animal; public Animal getAnimal() { return animal; } }
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication implements CommandLineRunner { @Autowired private AnimalKeeper4 animalKeeper; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println(animalKeeper.getAnimal().type()); } }
輸出:
Tiger
所有註解都成功地注入了依賴bean。
原因:所有這些都是通過使用限定符名稱tiger進行注入的,而容器中只有一個具有此名稱的bean。
場景5:使用限定符名稱不正確但欄位名稱正確的限定符
5.1@Resource的行為將不同於@Inject和@Autowired
使用@Resource–此處按名稱匹配優先。
AnimalKeeper5_1:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author:crelle * @className:AnimalKeeper5 * @version:1.0.0 * @date:2020/9/23 * @description: Scenario 5 : Using Qualifier with incorrect qualifier name , but with correct field name * Using @Resource – here Match by Name takes higher precedence. **/ @Component public class AnimalKeeper5_1 {
@Resource
@Qualifier(value = "incorrect")
private Animal tiger;
public Animal getTiger() { return tiger; }
}
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication implements CommandLineRunner { @Autowired private AnimalKeeper5_1 animalKeeper; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println(animalKeeper.getTiger().type()); } }
輸出:
Tiger
5.2 使用@Inject或@Autowired:限定符的優先順序高於欄位名。
AnimalKeeper5_2:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import javax.annotation.Resource; import javax.inject.Inject; /** * @author:crelle * @className:AnimalKeeper5_2 * @version:1.0.0 * @date:2020/9/23 * @description: Using @Inject or @Autowired:Qualifier has higher precedence over field name. **/ @Component public class AnimalKeeper5_2 { @Qualifier(value = "lion") @Autowired private Animal tiger; // @Autowired // @Qualifier(“incorrect”) // private Animal tiger; public Animal getAnimal() { return tiger; } }
import crelle.test.springframework.beans.factory.annotation.annotationtypes.test1.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication implements CommandLineRunner { @Autowired private AnimalKeeper5_2 animalKeeper; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println(animalKeeper.getAnimal().type()); } }
輸出
Lion