@Autowired, @Inject 和@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
- By Type匹配
- By Qualifier匹配
- By Name匹配
@Resource
- By Name匹配
- By Type匹配
- By Qualifier匹配(如果By Name找到匹配项,则忽略)
在下面的示例中,让我们看看这些注解是如何工作的。
这里,我们有Animal接口和两个实现Tiger和Lion。
Animal:
/** * @author:crelle * @className:Animal * @version:1.0.0 * @date:2020/9/23 * @description:XX **/ public interface Animal { String type(); }
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:接口类型(By Type)注入——使用@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;
所有的注解都在做同样的事情,即尝试By Type注入依赖项(Tiger和Lion). 因此Spring容器不知道要注入Tiger或者Lion,注入失败!
如果你确定要注入Tiger实现类,可以使用@Primary注解。
场景2:使用实例类型(By 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
所有的注解都得到了成功的注入。
原因-容器都在尝试By Type注入,而Animal的类型是具体的Tiger,所以注入没有歧义。
场景3:使用属性名称(By 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
所有注解都将成功注入。
原因:它是按照属性名称(By Name)注入的,每当我们在类上使用@Component时,类名本身就会自动注册为spring bean。
Tiger类用Spring容器注册为tiger bean,而tiger bean是容器中唯一可用的类,因此没有歧义。
场景4:使用具有正确限定符名称(By 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。
原因:所有这些都是通过使用限定符名称(By Qualifier)tiger进行注入的,而容器中只有一个具有此名称的bean。
场景5:使用限定符名称不正确但字段名称正确的限定符(By Qualifier)
5.1 @Resource的行为将不同于@Inject和@Autowired
使用@Resource–此处By Name优先权大于By Qualifier
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:By Qualifier的优先权高于By Name。
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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律