简体   繁体   中英

Spring Constructor Injection throws an error when more than one constructor has @Autowired

Spring documentation says this:

Only one annotated constructor per class can be marked as required, but multiple non-required constructors can be annotated. In that case, each is considered among the candidates and Spring uses the greediest constructor whose dependencies can be satisfied — that is, the constructor that has the largest number of arguments. The constructor resolution algorithm is the same as for non-annotated classes with overloaded constructors, just narrowing the candidates to annotated constructors.

I tested it and I get an error as soon as I have another constructor marked by @Autowired

package com.example.demo.constructorinjection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ConstructorInjectComponent {   

private InjectionServiceOne injectionServiceOne;

private InjectionServiceTwo injectionServiceTwo;

@Autowired(required = true)
public constructorInjectComponent(InjectionServiceOne injectionServiceOne,
        InjectionServiceTwo injectionServiceTwo) {
    this.injectionServiceOne = injectionServiceOne;
    this.injectionServiceTwo = injectionServiceTwo;
}

@Autowired(required = false)
public constructorInjectComponent(InjectionServiceTwo injectionServiceTwo) {
    this.injectionServiceTwo = injectionServiceTwo;
}

@Autowired(required = false)
public constructorInjectComponent(InjectionServiceOne injectionServiceOne) {
    this.injectionServiceOne = injectionServiceOne;
}

@Scheduled(fixedRate=1000L)
public void allFieldsConstructorInjectionTest() {
    System.err.println("constructorInjection " + injectionServiceOne.method() + " " + injectionServiceTwo.method());
}
}

Error:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'constructorInjectComponent': Invalid autowire-marked constructor: public com.example.demo.constructorinjection.constructorInjectComponent(com.example.demo.constructorinjection.InjectionServiceOne). Found constructor with 'required' Autowired annotation already: public com.example.demo.constructorinjection.constructorInjectComponent(com.example.demo.constructorinjection.InjectionServiceOne,com.example.demo.constructorinjection.InjectionServiceTwo) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:314) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1269) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]

Question:

Why can't I have more than one constructors marked with @Autowired ? Spring documentation clearly says I can have more than one constructor marked with @Autowired .

The @Autowired is processed by AutowiredAnnotationBeanPostProcessor which its javadoc has better description of this behaviour:

Only one constructor (at max) of any given bean class may declare this annotation with the 'required' parameter set to true, indicating the constructor to autowire when used as a Spring bean.

This statement talks about the case when 'required' = true .

So if 'required' = true , only one constructor (at max) can declare @Autowired .

If multiple non-required constructors declare the annotation, they will be considered as candidates for autowiring. The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen.

This statement implies the other case (ie 'required' = false ).

So if 'required' = false , it allows to have multiple constructors.


You can see this checking logic in the source codes of this for-loop , which the codes are well written which is quite easy to understand.

I did some tests, and this is what I found.

Only one constructor can be marked with @Autowired (where required=true will be the default). And that's it. No other constructor can be marked with @Autowired no matter what is the value of required. But multiple constructors can be marked with @Autowired but all of them must have required=false.

Check this page where I raised the issue. And this page where I made the request to improve documentation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM