@Autowired的构造函数调用如何工作? [英] How do constructor calls with @Autowired work?

查看:362
本文介绍了@Autowired的构造函数调用如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习Spring Boot框架,并且想了解@Autowired注释的工作方式.我知道在Spring Boot中我们有一个上下文,并且在该上下文中有可以通过@Autowired批注相互连接的bean,这是因为在Spring Boot中我们具有依赖项注入,但是构造函数是如何调用的?/p>

我有这样的服务

@Service
public class MyService {

    public MyService() {
        // do something
    }

}

在一个班上,我有:

public class MyClass {

    @Autowired
    MyService service;

}

问题是:

MyService的构造函数被调用并执行了做某事",还是将其称为空的构造函数,所以我不能依靠执行某事"这一事实吗?

解决方案

TL; DR

在创建bean时,Spring必须调用目标bean类包含的构造函数:

  1. 如果未定义构造函数-那么Spring将调用由编译器生成的隐式默认构造函数.
  2. 如果没有显式定义一个no-args构造函数,则由于没有定义其他构造函数,因此Spring会调用此构造函数.
  3. 如果定义了一个构造函数,它需要一些依赖关系,那么Spring将不得不调用该构造函数并为其提供依赖关系. (从Spring 4.3开始,您甚至不必使用@Autowired标记此构造函数.)
  4. 如果定义了多个args构造函数,则您将不得不解决歧义,因为Spring将不知道要选择哪个. (然后,您可以用@Autowired标记其中之一,或使用配置类来定义您的bean).

旁注

Spring IOC容器(应用程序上下文)负责保存bean并在需要时返回它们.要创建上下文,您必须告诉Spring在哪里寻找bean定义:您可以提供xml文件,java配置或启用给定程序包中组件的自动扫描.当创建Spring上下文时,它必须创建Bean.它将尝试调用构造函数,并为需要它们的bean提供任何依赖关系.

在您的示例中,将为上下文创建MyClass实例时,它将调用MyClass类的默认构造函数,然后通过反射设置其依赖性.

但是,场注入通常不是一个好主意,因为您在测试此类组件时可能会遇到问题.构造函数或二传手注入是一个更好的选择.

如果您将MyClass更改为:

public class MyClass {

    private MyService service;

    @Autowired
    public MyClass(MyService service) {
        this.service = service;
    }

}

在这里您提供自己的构造函数-请注意,在这种情况下,不会生成任何默认构造函数.因此,Spring将必须调用您提供的构造函数并满足其依赖性.如果没有可以注入的依赖项,则将引发异常.

请注意,即使没有Spring也可以使用您的课程:

MyService myService = new MyService();
MyClass myclass = new MyClass(myService);

通过使用Spring构造型标记您的类,并使用@Autowired,您只需启用Spring对上下文创建和依赖项注入的支持(在自动包扫描的情况下)

I'm learning the Spring Boot framework and I want to understand how the @Autowired annotation works. I know that in Spring Boot we have a context, and inside that context there are beans which can be connected to each other by the @Autowired annotation and that's because in Spring Boot we have dependency injection, but how is the constructor called?

I have a service like this:

@Service
public class MyService {

    public MyService() {
        // do something
    }

}

and in a class I have:

public class MyClass {

    @Autowired
    MyService service;

}

The question is:

Is the constructor of MyService called and the "do something" executed or will it call an empty constructor and so I can't rely on the fact that "do something" will be executed?

解决方案

TL;DR

When creating beans Spring will have to invoke constructors that the target bean class contains :

  1. If there is no constructor defined - then Spring will invoke the implicit default constructor generated by compiler.
  2. If there is a no-args constructor defined explicitly then Spring invoke this one since there is no other constructor defined.
  3. If there is a constructor defined, which requires some dependencies then Spring will have to invoke this one and provide dependencies for it. (Since Spring 4.3 you do not even have to mark this constructor with @Autowired).
  4. If there are multiple args constructor defined then you will have to resolve ambiguity, since Spring will not know which one to choose. (Then you can mark one of them with @Autowired or use configuration class to define your beans).

Side notes

Spring IOC container (application context) is responsible for holding beans and return them whenever it is asked to do so. To create a context you have to tell Spring where to look for bean definitions : you can provide xml file, java configuration or enable auto-scanning of components in given packages. When Spring context is being created it has to create beans. It will try to invoke constructors and provide any dependencies for beans that require them.

In your example when instance of MyClass will be created for the context, it will invoke default constructor of MyClass class and then set it's dependency via reflection.

However field injection is typically a bad idea as you might have problems with testing such components. Constructor or setter injection is a better choice.

If you changed your MyClass to :

public class MyClass {

    private MyService service;

    @Autowired
    public MyClass(MyService service) {
        this.service = service;
    }

}

here you provide your own constructor - note that there will be no default constructor generated in this case. So Spring will have to invoke constructor you provided and satisfy dependency for it. If there is no dependency that can be injected - an exception will be thrown.

Notice that you can use your classes even without Spring :

MyService myService = new MyService();
MyClass myclass = new MyClass(myService);

By marking your classes with Spring stereotypes and by using @Autowired you just enable spring support for context creation and dependency injection (in case of automated package scanning)

这篇关于@Autowired的构造函数调用如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆