ChatGPT解决这个技术问题 Extra ChatGPT

了解 Spring @Autowired 的用法

我正在阅读 spring 3.0.x 参考文档以了解 Spring Autowired 注释:

3.9.2 @Autowired and @Inject

我无法理解以下示例。我们是否需要在 XML 中做一些事情才能让它工作?

例 1

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

例 2

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
                    CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

两个类如何自动装配实现相同的接口并使用相同的类?

例子:

class Red implements Color
class Blue implements Color

class myMainClass{
    @Autowired 
    private Color color;

    draw(){
        color.design(); 
    } 
}

将调用哪种设计方法?如何确保调用 Red 类的设计方法而不是 Blue?


M
M. Deinum

TL;博士

@Autowired 注释让您无需自己在 XML 文件中进行连接(或任何其他方式),只需为您找到需要注入的内容并为您执行此操作。

完整解释

@Autowired 注释允许您跳过其他地方的注入内容配置并为您完成。假设您的包是 com.mycompany.movies,您必须将此标记放在您的 XML(应用程序上下文文件)中:

<context:component-scan base-package="com.mycompany.movies" />

此标签将执行自动扫描。假设每个必须成为 bean 的类都使用正确的注释进行注释,例如 @Component(对于简单 bean)或 @Controller(对于 servlet 控件)或 @Repository(对于 DAO 类),并且这些类在某处在包 com.mycompany.movies 下,Spring 将找到所有这些并为每个创建一个 bean。这是在对类的 2 次扫描中完成的——第一次它只是搜索需要成为 bean 的类并映射它需要进行的注入,然后在第二次扫描中注入 bean。当然,您可以在更传统的 XML 文件中或使用 @Configuration 类(或三者的任意组合)来定义您的 bean。

@Autowired 注释告诉 Spring 需要在哪里进行注入。如果将它放在方法 setMovieFinder 上,它会(通过前缀 set + @Autowired 注释)理解需要注入 bean。在第二次扫描中,Spring 搜索类型为 MovieFinder 的 bean,如果找到此类 bean,则将其注入此方法。如果它找到两个这样的 bean,您将得到一个 Exception。为了避免 Exception,您可以使用 @Qualifier 注释并告诉它注入两个 bean 中的哪一个,方法如下:

@Qualifier("redBean")
class Red implements Color {
   // Class code here
}

@Qualifier("blueBean")
class Blue implements Color {
   // Class code here
}

或者,如果您更喜欢在 XML 中声明 bean,它看起来像这样:

<bean id="redBean" class="com.mycompany.movies.Red"/>

<bean id="blueBean" class="com.mycompany.movies.Blue"/>

@Autowired 声明中,您还需要添加 @Qualifier 以告知要注入两个颜色 bean 中的哪一个:

@Autowired
@Qualifier("redBean")
public void setColor(Color color) {
  this.color = color;
}

如果您不想使用两个注释(@Autowired@Qualifier),您可以使用 @Resource 来组合这两个:

@Resource(name="redBean")
public void setColor(Color color) {
  this.color = color;
}

@Resource(您可以在此答案的第一条评论中阅读有关它的一些额外数据)使您无需使用两个注释,而是只使用一个。

我将再添加两条评论:

好的做法是使用 @Inject 而不是 @Autowired,因为它不是 Spring 特定的并且是 JSR-330 标准的一部分。另一个好的做法是将 @Inject / @Autowired 放在构造函数而不是方法上。如果将它放在构造函数上,则可以验证注入的 bean 不为空,并且在尝试启动应用程序时快速失败,并在需要实际使用 bean 时避免 NullPointerException。

更新:为了完成图片,我创建了一个关于 @Configuration 类的new question


只是为了完成你的真棒答案:'@Resource' 是 JSR-250 标准的一部分,并且除了简单的注入之外还有额外的语义(正如你所说,'@Autowired' 来自 Spring;而'@Inject' 是JSR-330) :)
如果 MovieFinder 是一个接口,并且我们有一个用于 MovieFinderImpl(bean id = movieFinder) 的 bean,那么 Spring 将按类型或名称自动注入它?
@jaskey - 这取决于您是否使用 @Qualifier。如果你这样做 - 按名称,如果不是 - 按类型。仅当您的上下文中只有一个 MovieFinder 类型的 bean 时,按类型才会起作用。超过 1 会导致异常。
@Avi,很棒的答案。但我不明白 @Autowired 注释如何在 示例 2 中的 prepare 方法上工作。它正在初始化 MovieRecommender,但从技术上讲,它是 NOT 设置器。
@KaranChadha - @Autowired 也适用于构造函数。它找到所需的依赖项并将它们注入构造函数。
A
Aaron Digulla

示例中没有说明“实现相同接口的类”。 MovieCatalog 是一种类型,而 CustomerPreferenceDao 是另一种类型。春天可以很容易地把它们区分开来。

在 Spring 2.x 中,bean 的连接主要通过 bean ID 或名称发生。 Spring 3.x 仍然支持这一点,但通常,您将拥有一个具有某种类型的 bean 实例——大多数服务都是单例的。为它们命名很乏味。所以 Spring 开始支持“按类型自动装配”。

这些示例展示了可用于将 bean 注入字段、方法和构造函数的各种方法。

XML 已经包含 Spring 需要的所有信息,因为您必须在每个 bean 中指定完全限定的类名。但是,您需要小心处理接口:

此自动装配将失败:

 @Autowired
 public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }

由于 Java 不会在字节码中保留参数名称,因此 Spring 无法再区分这两个 bean。解决方法是使用 @Qualifier

 @Autowired
 public void prepare( @Qualifier("bean1") Interface1 bean1,
     @Qualifier("bean2")  Interface1 bean2 ) { ... }

@AaronDigulla 那太好了。但是我想知道你如何调用函数prepare,将使用哪些参数来调用这个函数?
@NguyenQuangAnh 我没有调用该方法,Spring 会在创建 bean 时执行此操作。这恰好在注入 @Autowired 字段时发生。然后 Spring 将看到需要参数,并将使用与字段注入相同的规则来查找参数。
C
Cem Sultan

是的,您可以配置 Spring servlet 上下文 xml 文件来定义您的 bean(即类),以便它可以为您进行自动注入。但是,请注意,您必须进行其他配置才能启动并运行 Spring,而最好的方法是按照教程进行操作。

配置好 Spring 后,您可以在 Spring servlet 上下文 xml 文件中执行以下操作,以使上面的示例 1 起作用(请将 com.movies 的包名称替换为真正的包名称,如果这是第 3 方类,然后确保适当的 jar 文件位于类路径中):

<beans:bean id="movieFinder" class="com.movies.MovieFinder" />

或者如果 MovieFinder 类有一个带有原始值的构造函数,那么你可以这样,

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg value="100" />
</beans:bean>

或者如果 MovieFinder 类有一个期望另一个类的构造函数,那么你可以做这样的事情,

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg ref="otherBeanRef" />
</beans:bean>

...其中 'otherBeanRef' 是另一个具有对预期类的引用的 bean。


在 XML 中定义所有连接只是忽略了 @Autowired 的整个想法