简体   繁体   中英

@Autowired Constructor Spring

I have a class named as PoeticJuggler which has two constructors as follows:

 @Autowired(required=false)
    public PoeticJuggler(Sonnet29 poem)
    {
        super();
        this.poem=poem;
        System.out.println("Test to all");
    }

    @Autowired(required=false)
    public PoeticJuggler(TestConstJuggler tst)
    {
        super();
        this.poem=new Sonnet29();
        System.out.println("Test to Test Juggler");
    }
public PoeticJuggler(int beanBags,Poem poem)
    {
        super(beanBags);
        this.poem=poem;
    }

And the configuration file is like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />

    <bean id="duke" class="com.springinaction.springidol.beans.Juggler">
        <constructor-arg value="15"/>
    </bean>


    <bean id="sonnet29" class="com.springinaction.springidol.beans.Sonnet29">
    </bean>

    <bean id="testDuke" class="com.springinaction.springidol.beans.TestConstJuggler">
    </bean>

    <bean id="poeticDuke" class="com.springinaction.springidol.beans.PoeticJuggler">
    </bean>

    <bean id="theStage" class="com.springinaction.springidol.beans.Stage" factory-method="getInstance">
    </bean>
</beans>

When i run the following code:

public class BeanContext 
{
public static void main(String[] args) throws PerformanceException 
{
ApplicationContext ctx=new  ClassPathXmlApplicationContext("performancebean.xml");
Performer performer=(Performer)ctx.getBean("poeticDuke");
performer.perform();
}
}

i get the output as:

Test to Test Juggler JUGGLING 3 BEANBAGS

My confusion is that how spring is identifying which constructor to call, as both of the mentioned constructors are getting satisfied.

I tried to simulate the use case, to me it purely depends upon the order of constructors returns by the reflection when multiple constructors getting satisfied. try the below in the beanContext and let us know the order. Note** There is no grantee that reflection returns the order as its presents in code.

Constructor<MainClass>[] methods = <yourClass>.class.getConstructors();
    for (int i = 0; i < methods.length; i++) {
        Class<?>[] types = methods[i].getParameterTypes();
        System.out.println("Constructor "+i);
        for (int j = 0; j < types.length; j++) {
            System.out.println("Param Type" + types[j].getName());
        }
    }

UPDATE: To understand more clearly find the sorting logic found in AutoWireUtils.sortConstructors . this method being called once the spring get all constructors using the below line

candidates = (mbd.isNonPublicAccessAllowed() ?
                        beanClass.getDeclaredConstructors() : beanClass.getConstructors());

AutoWireUtils.sortConstructors

public static void sortFactoryMethods(Method[] factoryMethods) {
    Arrays.sort(factoryMethods, new Comparator<Method>() {
        @Override
        public int compare(Method fm1, Method fm2) {
            boolean p1 = Modifier.isPublic(fm1.getModifiers());
            boolean p2 = Modifier.isPublic(fm2.getModifiers());
            if (p1 != p2) {
                return (p1 ? -1 : 1);
            }
            int c1pl = fm1.getParameterTypes().length;
            int c2pl = fm2.getParameterTypes().length;
            return (new Integer(c1pl)).compareTo(c2pl) * -1;
        }
    });
}

So , it is purely based on Sort , in case both constructors has same weight then it is matter of how reflection returns the constructors.

In this situation Spring identifies the proper bean by constructor parameter type.

When Spring performs autowiring and finds that

@Autowired(required=false)
public PoeticJuggler(Sonnet29 poem) {
...

it reads its constructor parameter type com.springinaction.springidol.beans.Sonnet29 . Then it determines that there is only one bean with such a class in the context so it instantiates sonnet29 bean first then instantiates poeticDuke passing reference to sonnect29 as concstuctor arg.

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