1.11. 使用 JSR 330 标准注解

预计阅读时间: 7 分钟

Starting with Spring 3.0, Spring offers support for JSR-330 standard annotations (Dependency Injection). Those annotations are scanned in the same way as the Spring annotations. To use them, you need to have the relevant jars in your classpath. 从 Spring 3.0 开始,Spring 提供了对 JSR-330 标准注解(依赖注入)的支持。这些注解的扫描方式与 Spring 注解相同。要使用它们,你需要在类路径中包含相关的 jar 文件。

If you use Maven, the javax.inject artifact is available in the standard Maven repository ( https://repo1.maven.org/maven2/javax/inject/javax.inject/1/). You can add the following dependency to your file pom.xml: 如果你使用 Maven, javax.inject 工件可在标准 Maven

仓库(https://repo1.maven.org/maven2/javax/inject/javax.inject/1/)中找到。你可以将以下依赖项添加到你的文件 pom.xml 中:

<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>

(#beans-inject-named)1.11.1. Dependency Injection with@Inject and@Named

Instead of @Autowired, you can use @javax.inject.Inject as follows:

import javax.inject.Inject; public class SimpleMovieLister { private MovieFinder movieFinder; @Inject public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } public void listMovies() { this.movieFinder.findMovies(...); // ... } }
import javax.inject.Inject class SimpleMovieLister { @Inject lateinit var movieFinder: MovieFinder fun listMovies() { movieFinder.findMovies(...) // ... } }

As with @Autowired, you can use @Inject at the field level, method level and constructor-argument level. Furthermore, you may declare your injection point as a Provider, allowing for on-demand access to beans of shorter scopes or lazy access to other beans through a Provider.get() call. The following example offers a variant of the preceding example: 与 @Autowired 一样,你可以在字段级别、方法级别和构造函数参数级别使用 @Inject 。此外,你可以将你的注入点声明为 Provider ,允许按需访问短作用域的 bean 或通过 Provider.get() 调用以懒加载其他 bean。以下示例提供了先前示例的变体:

import javax.inject.Inject; import javax.inject.Provider; public class SimpleMovieLister { private Provider<MovieFinder> movieFinder; @Inject public void setMovieFinder(Provider<MovieFinder> movieFinder) { this.movieFinder = movieFinder; } public void listMovies() { this.movieFinder.get().findMovies(...); // ... } }
import javax.inject.Inject class SimpleMovieLister { @Inject lateinit var movieFinder: Provider<MovieFinder> fun listMovies() { movieFinder.get().findMovies(...) // ... } }

If you would like to use a qualified name for the dependency that should be injected, you should use the @Named annotation, as the following example shows: 如果你想为应注入的依赖项使用一个合格的名字,应使用 @Named 注解,如下例所示:

import javax.inject.Inject; import javax.inject.Named; public class SimpleMovieLister { private MovieFinder movieFinder; @Inject public void setMovieFinder(@Named("main") MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
import javax.inject.Inject import javax.inject.Named class SimpleMovieLister { private lateinit var movieFinder: MovieFinder @Inject fun setMovieFinder(@Named("main") movieFinder: MovieFinder) { this.movieFinder = movieFinder } // ... }

As with @Autowired, @Inject can also be used with java.util.Optional or @Nullable. This is even more applicable here, since @Inject does not have a required attribute. The following pair of examples show how to use @Inject and @Nullable: 与 @Autowired 一样, @Inject 也可以与 java.util.Optional@Nullable 一起使用。这在当前情况下尤其适用,因为 @Inject 没有 required 属性。以下两个示例展示了如何使用 @Inject@Nullable

public class SimpleMovieLister { @Inject public void setMovieFinder(Optional<MovieFinder> movieFinder) { // ... } }
public class SimpleMovieLister { @Inject public void setMovieFinder(@Nullable MovieFinder movieFinder) { // ... } }
class SimpleMovieLister { @Inject var movieFinder: MovieFinder? = null }

(#beans-named)1.11.2.@Named and@ManagedBean: Standard Equivalents to the@Component Annotation

1.11.2. @Named@ManagedBean@Component 注释的标准等效

Instead of @Component, you can use @javax.inject.Named or javax.annotation.ManagedBean, as the following example shows: 而不是 @Component ,你可以使用 @javax.inject.Namedjavax.annotation.ManagedBean ,如下例所示:

import javax.inject.Inject; import javax.inject.Named; @Named("movieListener") // @ManagedBean("movieListener") could be used as well public class SimpleMovieLister { private MovieFinder movieFinder; @Inject public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
import javax.inject.Inject import javax.inject.Named @Named("movieListener") // @ManagedBean("movieListener") could be used as well class SimpleMovieLister { @Inject lateinit var movieFinder: MovieFinder // ... }

It is very common to use @Component without specifying a name for the component. @Named can be used in a similar fashion, as the following example shows: 非常常见在未指定组件名称的情况下使用 @Component@Named 也可以以类似的方式使用,如下例所示:

import javax.inject.Inject; import javax.inject.Named; @Named public class SimpleMovieLister { private MovieFinder movieFinder; @Inject public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
import javax.inject.Inject import javax.inject.Named @Named class SimpleMovieLister { @Inject lateinit var movieFinder: MovieFinder // ... }

When you use @Named or @ManagedBean, you can use component scanning in the exact same way as when you use Spring annotations, as the following example shows: 当你使用 @Named@ManagedBean 时,你可以使用组件扫描的方式,与使用 Spring 注解时完全相同,如下例所示:

@Configuration @ComponentScan(basePackages = "org.example") public class AppConfig { // ... }
@Configuration @ComponentScan(basePackages = ["org.example"]) class AppConfig { // ... }

In contrast to @Component, the JSR-330 @Named and the JSR-250 @ManagedBean annotations are not composable. You should use Spring’s stereotype model for building custom component annotations. 与 @Component 相比,JSR-330 @Named 和 JSR-250 @ManagedBean 注解不可组合。你应使用 Spring 的 stereotypes 模型来构建自定义组件注解。

(#beans-standard-annotations-limitations)1.11.3. Limitations of JSR-330 Standard Annotations

1.11.3. JSR-330 标准注解的限制

When you work with standard annotations, you should know that some significant features are not available, as the following table shows: 当你使用标准注释时,应知道以下表格显示的一些重要功能不可用:

Table 6. Spring component model elements versus JSR-330 variants 表 6. Spring 组件模型元素与 JSR-330 变体对比

Spring 春天

javax.inject.*

javax.inject restrictions / comments javax.inject 限制 / 评论

@Autowired

@Inject

@Inject has no 'required' attribute. Can be used with Java 8’s Optional instead. @Inject 没有'required'属性。可以使用 Java 8 的 Optional 代替。

@Component

@Named / @ManagedBean

JSR-330 does not provide a composable model, only a way to identify named components. JSR-330 不提供可组合模型,只提供识别命名组件的方法。

@Scope("singleton")

@Singleton

The JSR-330 default scope is like Spring’s prototype. However, in order to keep it consistent with Spring’s general defaults, a JSR-330 bean declared in the Spring container is a singleton by default. In order to use a scope other than singleton, you should use Spring’s @Scope annotation. javax.inject also provides a @Scope annotation. Nevertheless, this one is only intended to be used for creating your own annotations. JSR-330 默认作用域类似于 Spring 的 prototype 。然而,为了与 Spring 的一般默认值保持一致,在 Spring 容器中声明的 JSR-330 Bean 默认为 singleton 。若要使用除 singleton 之外的作用域,应使用 Spring 的 @Scope 注解。 javax.inject 还提供了一个@Scope 注解。不过,这个注解仅用于创建自己的注解。

@Qualifier

@Qualifier / @Named

javax.inject.Qualifier is just a meta-annotation for building custom qualifiers. Concrete String qualifiers (like Spring’s @Qualifier with a value) can be associated through javax.inject.Named. javax.inject.Qualifier 只是一个用于构建自定义限定符的元注解。具体的 String 限定符(如带有值的 Spring 的 @Qualifier )可以通过 javax.inject.Named 关联。

@Value

-

no equivalent 无对应项

@Required

-

no equivalent 无对应项

@Lazy

-

no equivalent 无对应项

ObjectFactory 对象工厂

Provider 供应商

javax.inject.Provider is a direct alternative to Spring’s ObjectFactory, only with a shorter get() method name. It can also be used in combination with Spring’s @Autowired or with non-annotated constructors and setter methods. javax.inject.Provider 是 Spring 的 ObjectFactory 的直接替代品,只是方法名更短。它还可以与 Spring 的 @Autowired 结合使用,或者与非注解的构造函数和设置方法一起使用。