ChatGPT解决这个技术问题 Extra ChatGPT

Spring injects dependencies in constructor without @Autowired annotation

I'm experimenting with examples from this official Spring tutorials and there is a dependency on this code:
https://github.com/spring-guides/gs-async-method/tree/master/complete

If you look at the code on AppRunner.java class, I have 2 questions:

When server is starting, if I put a breakpoint in this class's constructor, seems like in the constructor, the GitHubLookupService is provided by spring, using the @Service bean that was configured. BUT, there was no @Autowired annotation on the constructor, so how in the world this constructor get called with the right dependency? It was supposed to be null.

Is it an automatic assumption of Spring Boot? Does Spring see "private field + constructor argument, and it assumes it should look for an appropriate bean? Is it Spring Framework or Spring boot? Am I missing something?

As I remember, it was mendatory to provide default constructor to beans / service etc. How come this class (AppRunner) doesn't have a default constructor? How does Spring knows that it should run the constructor with the argument? Is it because it is the only constructor?


M
M. Deinum

Starting with Spring 4.3, if a class, which is configured as a Spring bean, has only one constructor, the @Autowired annotation can be omitted and Spring will use that constructor and inject all necessary dependencies.

Regarding the default constructor: You either need the default constructor, a constructor with the @Autowired annotation when you have multiple constructors, or only one constructor in your class with or without the @Autowired annotation.

Read the @Autowired chapter from the official Spring documentation for more information.


A more relevant link to documentation would be docs.spring.io/spring/docs/4.3.x/spring-framework-reference/…
I have a similar issue, only that my class is not annotated as Bean! In fact, it isn't annotated at all! Still Spring tries to autowire the constructor and fails, because no Bean was found that matches the type of the constructor parameter. The class does however extend PropertySource. Could that be the cause? Is there a way to avoid that autowiring?
Here the quote from the official documentation : As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean only defines one constructor to begin with. However, if several constructors are available, at least one must be annotated to teach the container which one to use.
M
Michael

Think of it this way... Suppose you have the following component:

@Component 
public class FooService {
    public FooService(Bar bar) { /*whatever*/ }
}

When Spring is scanning this class, it wants to know how it should go about constructing an instance. It's using reflection so it can get a list of all of the constructors at runtime.

In this case, it is completely unambiguous how Spring must construct this instance. There's only one constructor so there is no decision to be made, and no ambiguity at all.

If you add @Autowired here, you are not narrowing anything down, and you are not giving Spring any extra information to help make its decision - its decision is already made because there is only one candidate.

And so, as a convenience, the Spring team decided @Autowired should be optional. Since its not helping the Spring framework to make a decision, its presence is just noise.

If your component has multiple constructors then you can use @Autowired on one of them to tell Spring "use this one, not that one".


Good explanation, totally makes sense. Thanks. I simply created a service class annotated it with @Service & was trying to do the autowire Service srv; in my Controller class & was expecting Spring to get me the bean of this service assuming it would use the Default constructor implementation. But instead I either need to provide a No-Argument or a Parameterized constructor.