简体   繁体   中英

Some doubts about how exactly work the XML constructor injection Spring configuration?

I am studying Sping XML configuration and I have the following doubt related to the constructor injection configuration .

So I have the following example:

<bean id=“transferService” class=“com.acme.TransferServiceImpl”>
    <constructor-arg ref=“accountRepository”/>
    <constructor-arg ref=“customerRepository”/>
</bean>

<bean id=“accountRepository” class=“com.acme.AccountRepositoryImpl”/>
<bean id=“customerRepository” class=“com.acme.CustomerRepositoryImpl”/>

Ok. It is pretty clear for me what happens: first the accountRepository bean is created as an com.acme.AccountRepositoryImpl instance and the customerRepository bean is created as an com.acme.CustomerRepositoryImpl instance

Then is created the transferService bean as an istance of the com.acme.TransferServiceImpl class and the previous 2 bean are injected as input paramether of the constructor during the bean construction.

This is clear. My doubt is related to the fact that on the documentation I read that:

Parameters injected according to their type

What it exactly means? It seems to me that in the previous configuration the beans are injected according to their id.

The previous statement means that Spring check the type and for example if the constructor of the TransferServiceImpl class take 2 paramethers having type AccountRepositoryImpl and CustomerRepositoryImpl it perform the matching?

So it means that:

<bean id=“transferService” class=“com.acme.TransferServiceImpl”>
    <constructor-arg ref=“accountRepository”/>
    <constructor-arg ref=“customerRepository”/>
</bean>

is the same thing of:

<bean id=“transferService” class=“com.acme.TransferServiceImpl”>
    <constructor-arg ref=“customerRepository”/>
    <constructor-arg ref=“accountRepository”/>
</bean>

?

Changing the order of the paramethers the result don't change because Spring perform the matching for me? If yes what happens if in the constructor I have more paramether that have the same type?

Tnx

If every constructor parameter has different type - Spring handles it automatically - you can mix order in XML code. If there is more than one with the same type then Spring just puts them in the same order as they appear in the constructor definition. Let's take following example:

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }
}

public class Project {
    private User user1;
    private User user2;
    private int cost;

    public Project(User user1, User user2, int cost) {
        this.user1 = user1;
        this.user2 = user2;
        this.cost = cost;
    }
}

Bean definition like:

<bean id="user1" class="demo.User">
    <constructor-arg value="User1" />
</bean>

<bean id="user2" class="demo.User">
    <constructor-arg value="User2" />
</bean>

<bean id="proj" class="demo.Project">
    <constructor-arg value="100" />
    <constructor-arg ref="user2" />
    <constructor-arg ref="user1" />
</bean>

Will be handled by Spring without throwing exceptions and it will result with the object of class Project with property:

  • user1 = bean(user2)
  • user2 = bean(user1)
  • cost = 100

If you want to make things right, always set index for constructor-arg:

<bean id="proj" class="demo.Project">
    <constructor-arg index="0" ref="user1" />
    <constructor-arg index="1" ref="user2" />
    <constructor-arg index="2" value="100" />
</bean>

or for even better readability - set name property:

<bean id="proj" class="demo.Project">
    <constructor-arg name="cost" value="100" />
    <constructor-arg name="user2" ref="user2" />
    <constructor-arg name="user1" ref="user1" />
</bean>

Just keep in mind that:

(...) to make this work out of the box your code must be compiled with the debug flag enabled so that Spring can look up the parameter name from the constructor. If you can't compile your code with debug flag (or don't want to) you can use @ConstructorProperties JDK annotation to explicitly name your constructor arguments.

Read more in Spring reference

Following is the way to handle ambiguity in constructor based injection:

Scenario 1: If you have multiple parameters, you need to use the type attribute. eg

<constructor-arg ref=“accountRepository” type="com.acme.AccountRepositoryImpl" />
<constructor-arg ref=“customerRepository” type="com.acme.CustomerRepositoryImpl" />

Scenario 2: If you have multiple parameters of same type, you need to use the index attribute eg

<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>

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