Spring 中的注解:@Autowired、@Resource 和@Inject
1.概述
在本 Spring Framework 教程中,我们将演示如何使用与依赖注入相关的注解,即*@Resource*、@Inject和*@Autowired*注解。这些注解为类提供了一种声明性的方式来解决依赖关系:
@Autowired
ArbitraryClass arbObject;
与直接实例化它们相反(命令式):
ArbitraryClass arbObject = new ArbitraryClass();
三个注解中有两个属于 Java 扩展包:javax.annotation.Resource和javax.inject.Inject。@Autowired注解属于org.springframework.beans.factory.annotation包。
这些注解中的每一个都可以通过字段注入或 setter 注入来解决依赖关系。我们将使用一个简化但实用的示例来演示三个注释之间的区别,基于每个注释所采用的执行路径。
这些示例将重点介绍如何在集成测试期间使用三个注入注解。测试所需的依赖可以是任意文件或任意类。
2. @Resource注解
@Resource注释是JSR-250 注释集合的一部分,并与 Jakarta EE 一起打包。此注解具有以下执行路径,按优先级列出:
- 按名称匹配
- 按类型匹配
- 按预选赛匹配
这些执行路径适用于 setter 和 field 注入。
2.1. 字段注入
我们可以通过使用*@Resource*注释来注释实例变量来通过字段注入来解决依赖关系。
2.1.1. 按名称匹配
我们将使用以下集成测试来演示按名称匹配字段注入:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestResourceNameType.class)
public class FieldResourceInjectionIntegrationTest {
@Resource(name="namedFile")
private File defaultFile;
@Test
public void givenResourceAnnotation_WhenOnField_ThenDependencyValid(){
assertNotNull(defaultFile);
assertEquals("namedFile.txt", defaultFile.getName());
}
}
让我们看一下代码。在FieldResourceInjectionTest集成测试中,在第 7 行,我们通过将 bean 名称作为属性值传递给*@Resource*注释来按名称解析依赖项:
@Resource(name="namedFile")
private File defaultFile;
此配置将使用按名称匹配执行路径解析依赖关系。我们必须在ApplicationContextTestResourceNameType应用程序上下文中定义 bean namedFile。
注意 bean id 和对应的引用属性值必须匹配:
@Configuration
public class ApplicationContextTestResourceNameType {
@Bean(name="namedFile")
public File namedFile() {
File namedFile = new File("namedFile.txt");
return namedFile;
}
}
如果我们未能在应用程序上下文中定义 bean,它将导致org.springframework.beans.factory.NoSuchBeanDefinitionException被抛出。我们可以通过更改ApplicationContextTestResourceNameType应用程序上下文中传递给*@Bean注解的属性值,或者更改FieldResourceInjectionTest集成测试中传递给@Resource*注解的属性值来证明这一点。
2.1.2. 按类型匹配
为了演示按类型匹配的执行路径,我们只删除了FieldResourceInjectionTest集成测试第 7 行的属性值:
@Resource
private File defaultFile;
然后我们再次运行测试。 测试仍然会通过,因为如果*@Resource*注释没有接收到 bean 名称作为属性值,Spring 框架将继续进行下一级优先级,按类型匹配,以尝试解决依赖关系。
2.1.3. 按限定符匹配
为了演示按限定符匹配执行路径,将修改集成测试场景,以便在ApplicationContextTestResourceQualifier应用程序上下文中定义两个 bean:
@Configuration
public class ApplicationContextTestResourceQualifier {
@Bean(name="defaultFile")
public File defaultFile() {
File defaultFile = new File("defaultFile.txt");
return defaultFile;
}
@Bean(name="namedFile")
public File namedFile() {
File namedFile = new File("namedFile.txt");
return namedFile;
}
}
我们将使用QualifierResourceInjectionTest集成测试来演示逐个匹配的依赖关系解析。在这种情况下,需要将特定的 bean 依赖注入到每个引用变量中:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestResourceQualifier.class)
public class QualifierResourceInjectionIntegrationTest {
@Resource
private File dependency1;
@Resource
private File dependency2;
@Test
public void givenResourceAnnotation_WhenField_ThenDependency1Valid(){
assertNotNull(dependency1);
assertEquals("defaultFile.txt", dependency1.getName());
}
@Test
public void givenResourceQualifier_WhenField_ThenDependency2Valid(){
assertNotNull(dependency2);
assertEquals("namedFile.txt", dependency2.getName());
}
}
当我们运行集成测试时,会抛出org.springframework.beans.factory.NoUniqueBeanDefinitionException 。这会发生,因为应用程序上下文将找到两个File类型的 bean 定义,并且不知道哪个 bean 应该解决依赖关系。
要解决这个问题,我们需要参考QualifierResourceInjectionTest集成测试的第 7 行到第 10 行:
@Resource
private File dependency1;
@Resource
private File dependency2;
我们必须添加以下代码行:
@Qualifier("defaultFile")
@Qualifier("namedFile")
使代码块如下所示:
@Resource
@Qualifier("defaultFile")
private File dependency1;
@Resource
@Qualifier("namedFile")
private File dependency2;
当我们再次运行集成测试时,它应该会通过。我们的测试表明,即使我们在应用程序上下文中定义了多个 bean,我们也可以使用*@Qualifier*注释通过允许我们将特定的依赖项注入到一个类中来消除任何混淆。
2.2. setter注入
在字段上注入依赖项时所采用的执行路径也适用于基于 setter 的注入。
2.2.1. 按名称匹配
唯一的区别是MethodResourceInjectionTest集成测试有一个 setter 方法:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestResourceNameType.class)
public class MethodResourceInjectionIntegrationTest {
private File defaultFile;
@Resource(name="namedFile")
protected void setDefaultFile(File defaultFile) {
this.defaultFile = defaultFile;
}
@Test
public void givenResourceAnnotation_WhenSetter_ThenDependencyValid(){
assertNotNull(defaultFile);
assertEquals("namedFile.txt", defaultFile.getName());
}
}
我们通过注解引用变量的相应 setter 方法,通过 setter 注入来解决依赖关系。然后我们将bean依赖的名称作为属性值传递给*@Resource*注解:
private File defaultFile;
@Resource(name="namedFile")
protected void setDefaultFile(File defaultFile) {
this.defaultFile = defaultFile;
}
在本例中,我们将重用namedFile bean 依赖项。bean 名称和相应的属性值必须匹配。 当我们运行集成测试时,它将通过。
为了让我们验证按名称匹配执行路径是否解决了依赖关系,我们需要将传递给*@Resource注解的属性值更改为我们选择的值并再次运行测试。这一次,测试将失败并出现NoSuchBeanDefinitionException*。
2.2.2. 按类型匹配
为了演示基于setter、按类型匹配的执行,我们将使用MethodByTypeResourceTest集成测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestResourceNameType.class)
public class MethodByTypeResourceIntegrationTest {
private File defaultFile;
@Resource
protected void setDefaultFile(File defaultFile) {
this.defaultFile = defaultFile;
}
@Test
public void givenResourceAnnotation_WhenSetter_ThenValidDependency(){
assertNotNull(defaultFile);
assertEquals("namedFile.txt", defaultFile.getName());
}
}
当我们运行这个测试时,它会通过。 为了让我们验证按类型匹配的执行路径是否解决了File依赖关系,我们需要将defaultFile变量的类类型更改为另一个类类型,如String。然后我们可以再次执行MethodByTypeResourceTest集成测试,这次会抛出NoSuchBeanDefinitionException 。
该异常验证是否确实使用了按类型匹配来解决文件依赖关系。NoSuchBeanDefinitionException确认引用变量名称不需要与 bean 名称匹配。相反,依赖解析取决于 bean 的类类型与引用变量的类类型匹配。
2.2.3. 按限定符匹配
我们将使用MethodByQualifierResourceTest集成测试来演示按限定符匹配执行路径:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestResourceQualifier.class)
public class MethodByQualifierResourceIntegrationTest {
private File arbDependency;
private File anotherArbDependency;
@Test
public void givenResourceQualifier_WhenSetter_ThenValidDependencies(){
assertNotNull(arbDependency);
assertEquals("namedFile.txt", arbDependency.getName());
assertNotNull(anotherArbDependency);
assertEquals("defaultFile.txt", anotherArbDependency.getName());
}
@Resource
@Qualifier("namedFile")
public void setArbDependency(File arbDependency) {
this.arbDependency = arbDependency;
}
@Resource
@Qualifier("defaultFile")
public void setAnotherArbDependency(File anotherArbDependency) {
this.anotherArbDependency = anotherArbDependency;
}
}
我们的测试表明,即使我们在应用程序上下文中定义了特定类型的多个 bean 实现,我们也可以使用*@Qualifier注释和@Resource*注释来解决依赖关系。
类似于基于字段的依赖注入,如果我们在一个应用上下文中定义多个bean,我们必须使用 @Qualifier注解来指定使用哪个bean来解析依赖,否则会抛出NoUniqueBeanDefinitionException。
3. @Inject注解
@Inject注释属于JSR-330 注释集合。此注解具有以下执行路径,按优先级列出:
- 按类型匹配
- 按预选赛匹配
- 按名称匹配
这些执行路径适用于 setter 和 field 注入。为了让我们访问*@Inject注解,我们必须将javax.inject*库声明为 Gradle 或 Maven 依赖项。
对于 Gradle:
testCompile group: 'javax.inject', name: 'javax.inject', version: '1'
对于maven:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
3.1. 字段注入
3.1.1. 按类型匹配
我们将修改集成测试示例以使用另一种类型的依赖项,即ArbitraryDependency类。ArbitraryDependency类依赖仅作为一个简单的依赖,并没有进一步的意义:
@Component
public class ArbitraryDependency {
private final String label = "Arbitrary Dependency";
public String toString() {
return label;
}
}
这是有问题的FieldInjectTest集成测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestInjectType.class)
public class FieldInjectIntegrationTest {
@Inject
private ArbitraryDependency fieldInjectDependency;
@Test
public void givenInjectAnnotation_WhenOnField_ThenValidDependency(){
assertNotNull(fieldInjectDependency);
assertEquals("Arbitrary Dependency",
fieldInjectDependency.toString());
}
}
与*@Resource注解首先按名称解析依赖关系不同,@Inject*注解的默认行为是按类型解析依赖关系。
这意味着即使类引用变量名称与 bean 名称不同,依赖关系仍然会被解析,前提是 bean 是在应用程序上下文中定义的。请注意以下测试中引用变量名称的方式:
@Inject
private ArbitraryDependency fieldInjectDependency;
与应用程序上下文中配置的 bean 名称不同:
@Bean
public ArbitraryDependency injectDependency() {
ArbitraryDependency injectDependency = new ArbitraryDependency();
return injectDependency;
}
当我们执行测试时,我们能够解决依赖关系。
3.1.2. 按限定符匹配
如果一个特定的类类型有多个实现,并且某个类需要一个特定的 bean,该怎么办?让我们修改集成测试示例,使其需要另一个依赖项。 在此示例中,我们将在按类型匹配示例中使用的ArbitraryDependency类子类化,以创建AnotherArbitraryDependency类:
public class AnotherArbitraryDependency extends ArbitraryDependency {
private final String label = "Another Arbitrary Dependency";
public String toString() {
return label;
}
}
每个测试用例的目标是确保我们将每个依赖项正确地注入每个引用变量中:
@Inject
private ArbitraryDependency defaultDependency;
@Inject
private ArbitraryDependency namedDependency;
我们可以使用FieldQualifierInjectTest集成测试来演示限定符匹配:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestInjectQualifier.class)
public class FieldQualifierInjectIntegrationTest {
@Inject
private ArbitraryDependency defaultDependency;
@Inject
private ArbitraryDependency namedDependency;
@Test
public void givenInjectQualifier_WhenOnField_ThenDefaultFileValid(){
assertNotNull(defaultDependency);
assertEquals("Arbitrary Dependency",
defaultDependency.toString());
}
@Test
public void givenInjectQualifier_WhenOnField_ThenNamedFileValid(){
assertNotNull(defaultDependency);
assertEquals("Another Arbitrary Dependency",
namedDependency.toString());
}
}
如果我们在应用程序上下文中有多个特定类的实现,并且FieldQualifierInjectTest集成测试尝试以下面列出的方式注入依赖项,则会抛出NoUniqueBeanDefinitionException :
@Inject
private ArbitraryDependency defaultDependency;
@Inject
private ArbitraryDependency namedDependency;
抛出这个异常是 Spring 框架指出某个类有多个实现的方式,它对使用哪一个感到困惑。为了阐明混淆,我们可以转到FieldQualifierInjectTest集成测试的第 7 行和第 10 行:
@Inject
private ArbitraryDependency defaultDependency;
@Inject
private ArbitraryDependency namedDependency;
我们可以将所需的 bean 名称传递给*@Qualifier注释,我们将其与@Inject*注释一起使用。这就是代码块现在的样子:
@Inject
@Qualifier("defaultFile")
private ArbitraryDependency defaultDependency;
@Inject
@Qualifier("namedFile")
private ArbitraryDependency namedDependency;
@Qualifier注解在接收 bean 名称时要求严格匹配。我们必须确保将 bean 名称正确传递给Qualifier,否则将抛出NoUniqueBeanDefinitionException。如果我们再次运行测试,它应该会通过。
3.1.3. 按名称匹配
用于演示按名称匹配的FieldByNameInjectTest集成测试类似于按类型匹配执行路径。唯一的区别是现在我们需要一个特定的 bean,而不是一个特定的类型。在此示例中,我们再次对ArbitraryDependency类进行子类化以生成YetAnotherArbitraryDependency类:
public class YetAnotherArbitraryDependency extends ArbitraryDependency {
private final String label = "Yet Another Arbitrary Dependency";
public String toString() {
return label;
}
}
为了演示按名称匹配的执行路径,我们将使用以下集成测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestInjectName.class)
public class FieldByNameInjectIntegrationTest {
@Inject
@Named("yetAnotherFieldInjectDependency")
private ArbitraryDependency yetAnotherFieldInjectDependency;
@Test
public void givenInjectQualifier_WhenSetOnField_ThenDependencyValid(){
assertNotNull(yetAnotherFieldInjectDependency);
assertEquals("Yet Another Arbitrary Dependency",
yetAnotherFieldInjectDependency.toString());
}
}
我们列出应用程序上下文:
@Configuration
public class ApplicationContextTestInjectName {
@Bean
public ArbitraryDependency yetAnotherFieldInjectDependency() {
ArbitraryDependency yetAnotherFieldInjectDependency =
new YetAnotherArbitraryDependency();
return yetAnotherFieldInjectDependency;
}
}
如果我们运行集成测试,它将通过。
为了验证我们是否通过按名称匹配执行路径注入了依赖项,我们需要将传入*@Named注释的值yetAnotherFieldInjectDependency更改为我们选择的另一个名称。当我们再次运行测试时,会抛出NoSuchBeanDefinitionException*。
3.2. setter注入
@Inject注解的基于设置器的注入类似于用于基于*@Resource*设置器的注入的方法。我们不是注释引用变量,而是注释相应的 setter 方法。基于字段的依赖注入所遵循的执行路径也适用于基于 setter 的注入。
4. @Autowired注解
@Autowired注解的行为类似于*@Inject注解。唯一的区别是@Autowired注解是 Spring 框架的一部分。此注解与@Inject*注解具有相同的执行路径,按优先顺序列出:
- 按类型匹配
- 按预选赛匹配
- 按名称匹配
这些执行路径适用于 setter 和 field 注入。
4.1. 字段注入
4.1.1. 按类型匹配
用于演示*@Autowired按类型匹配执行路径的集成测试示例将类似于用于演示@Inject按类型匹配执行路径的测试。我们使用以下FieldAutowiredTest集成测试来演示使用@Autowired*注释的按类型匹配:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestAutowiredType.class)
public class FieldAutowiredIntegrationTest {
@Autowired
private ArbitraryDependency fieldDependency;
@Test
public void givenAutowired_WhenSetOnField_ThenDependencyResolved() {
assertNotNull(fieldDependency);
assertEquals("Arbitrary Dependency", fieldDependency.toString());
}
}
我们列出了此集成测试的应用程序上下文:
@Configuration
public class ApplicationContextTestAutowiredType {
@Bean
public ArbitraryDependency autowiredFieldDependency() {
ArbitraryDependency autowiredFieldDependency =
new ArbitraryDependency();
return autowiredFieldDependency;
}
}
我们使用此集成测试来证明按类型匹配优先于其他执行路径。注意FieldAutowiredTest集成测试第 8 行的引用变量名称:
@Autowired
private ArbitraryDependency fieldDependency;
这与应用程序上下文中的 bean 名称不同:
@Bean
public ArbitraryDependency autowiredFieldDependency() {
ArbitraryDependency autowiredFieldDependency =
new ArbitraryDependency();
return autowiredFieldDependency;
}
当我们运行测试时,它应该通过了。 为了确认依赖确实是使用 match-by-type 执行路径解决的,我们需要更改fieldDependency引用变量的类型并再次运行集成测试。这一次,FieldAutowiredTest集成测试将失败,并引发NoSuchBeanDefinitionException。这验证了我们使用了按类型匹配来解决依赖关系。
4.1.2. 按限定符匹配
如果我们遇到在应用程序上下文中定义了多个 bean 实现的情况怎么办:
@Configuration
public class ApplicationContextTestAutowiredQualifier {
@Bean
public ArbitraryDependency autowiredFieldDependency() {
ArbitraryDependency autowiredFieldDependency =
new ArbitraryDependency();
return autowiredFieldDependency;
}
@Bean
public ArbitraryDependency anotherAutowiredFieldDependency() {
ArbitraryDependency anotherAutowiredFieldDependency =
new AnotherArbitraryDependency();
return anotherAutowiredFieldDependency;
}
}
如果我们执行以下FieldQualifierAutowiredTest集成测试,将抛出NoUniqueBeanDefinitionException :
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestAutowiredQualifier.class)
public class FieldQualifierAutowiredIntegrationTest {
@Autowired
private ArbitraryDependency fieldDependency1;
@Autowired
private ArbitraryDependency fieldDependency2;
@Test
public void givenAutowiredQualifier_WhenOnField_ThenDep1Valid(){
assertNotNull(fieldDependency1);
assertEquals("Arbitrary Dependency", fieldDependency1.toString());
}
@Test
public void givenAutowiredQualifier_WhenOnField_ThenDep2Valid(){
assertNotNull(fieldDependency2);
assertEquals("Another Arbitrary Dependency",
fieldDependency2.toString());
}
}
异常是由于应用程序上下文中定义的两个 bean 引起的歧义。Spring 框架不知道哪个 bean 依赖项应该自动装配到哪个引用变量。我们可以通过在FieldQualifierAutowiredTest集成测试的第 7 行和第 10 行添加*@Qualifier*注释来解决此问题:
@Autowired
private FieldDependency fieldDependency1;
@Autowired
private FieldDependency fieldDependency2;
使代码块如下所示:
@Autowired
@Qualifier("autowiredFieldDependency")
private FieldDependency fieldDependency1;
@Autowired
@Qualifier("anotherAutowiredFieldDependency")
private FieldDependency fieldDependency2;
当我们再次运行测试时,它将通过。
4.1.3. 按名称匹配
我们将使用相同的集成测试场景来演示使用*@Autowired注解注入字段依赖项的按名称匹配执行路径。当按名称自动装配依赖项时,@ComponentScan注解必须与应用程序上下文ApplicationContextTestAutowiredName*一起使用:
@Configuration
@ComponentScan(basePackages={"com.blogdemo.dependency"})
public class ApplicationContextTestAutowiredName {
}
我们使用*@ComponentScan注解在包中搜索已使用@Component注解进行注解的Java类。例如,在应用程序上下文中,将扫描com.blogdemo.dependency包以查找已使用@Component注释进行注释的类。在这种情况下,Spring 框架必须检测ArbitraryDependency类,该类具有@Component*注解:
@Component(value="autowiredFieldDependency")
public class ArbitraryDependency {
private final String label = "Arbitrary Dependency";
public String toString() {
return label;
}
}
传递到*@Component注释的属性值autowiredFieldDependency告诉 Spring 框架ArbitraryDependency类是一个名为autowiredFieldDependency的组件。为了让@Autowired注解通过名称解析依赖,组件名称必须与FieldAutowiredNameTest*集成测试中定义的字段名称相对应;请参考第8行:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestAutowiredName.class)
public class FieldAutowiredNameIntegrationTest {
@Autowired
private ArbitraryDependency autowiredFieldDependency;
@Test
public void givenAutowiredAnnotation_WhenOnField_ThenDepValid(){
assertNotNull(autowiredFieldDependency);
assertEquals("Arbitrary Dependency",
autowiredFieldDependency.toString());
}
}
当我们运行FieldAutowiredNameTest集成测试时,它将通过。 但是我们怎么知道*@Autowired注解确实调用了按名称匹配的执行路径呢?我们可以将引用变量autowiredFieldDependency*的名称更改为我们选择的另一个名称,然后再次运行测试。
这一次,测试将失败并抛出NoUniqueBeanDefinitionException。类似的检查是将*@Component属性值autowiredFieldDependency*更改为我们选择的另一个值并再次运行测试。NoUniqueBeanDefinitionException也会被抛出。
这个异常证明如果我们使用不正确的 bean 名称,将找不到有效的 bean。这就是我们知道调用了按名称匹配执行路径的方式。
4.2. setter注入
@Autowired注解的基于设置器的注入类似于为基于*@Resource*设置器的注入演示的方法。我们不是用@Inject注解来注解引用变量,而是注解对应的setter。基于字段的依赖注入所遵循的执行路径也适用于基于 setter 的注入。
5. 应用这些注释
这就提出了应该使用哪种注释以及在什么情况下使用的问题。这些问题的答案取决于相关应用程序面临的设计场景,以及开发人员希望如何利用基于每个注释的默认执行路径的多态性。
5.1. 通过多态性在应用程序范围内使用单例
如果设计是这样的应用程序行为基于接口或抽象类的实现,并且这些行为在整个应用程序中使用,那么我们可以使用*@Inject或@Autowired*注解。 这种方法的好处是,当我们升级应用程序或应用补丁来修复错误时,可以将类换出,而对整体应用程序行为的负面影响最小。在这种情况下,主要的默认执行路径是按类型匹配。
5.2. 通过多态进行细粒度的应用程序行为配置
如果设计使得应用程序具有复杂的行为,每个行为都基于不同的接口/抽象类,并且每个实现的用法在应用程序中有所不同,那么我们可以使用*@Resource*注解。在这种情况下,主要的默认执行路径是按名称匹配。
5.3. 依赖注入应该由 Jakarta EE 平台单独处理
如果 Jakarta EE 平台而不是 Spring 注入所有依赖项的设计要求,那么选择是在*@Resource注释和@Inject*注释之间进行选择。我们应该根据需要哪个默认执行路径来缩小两个注释之间的最终决定。
5.4. 依赖注入应该由 Spring 框架单独处理
如果要求所有依赖项都由 Spring Framework 处理,则唯一的选择是*@Autowired*注释。
5.5. 讨论总结
下表总结了我们的讨论。
设想 | @Resource | @Inject | @Autowired |
---|---|---|---|
通过多态性在应用程序范围内使用单例 | ✗ | ✔ | ✔ |
通过多态进行细粒度的应用程序行为配置 | ✔ | ✗ | ✗ |
依赖注入应该由 Jakarta EE 平台单独处理 | ✔ | ✔ | ✗ |
依赖注入应该由 Spring Framework 单独处理 | ✗ | ✗ | ✔ |