Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autowiring conflict in spring core with the xml configuration

Taking as reference the post Spring @Autowired and @Qualifier

We have this example to fix the autowiring conflict :

public interface Vehicle {
     public void start();
     public void stop();
}

There are two beans, Car and Bike implements Vehicle interface.

@Component(value="car")
public class Car implements Vehicle {

     @Override
     public void start() {
           System.out.println("Car started");
     }

     @Override
     public void stop() {
           System.out.println("Car stopped");
     }
 }

@Component(value="bike")
public class Bike implements Vehicle {

     @Override
     public void start() {
          System.out.println("Bike started");
     }

     @Override
     public void stop() {
          System.out.println("Bike stopped");
     }
}

@Component
public class VehicleService {

    @Autowired
    @Qualifier("bike")
    private Vehicle vehicle;

    public void service() {
         vehicle.start();
         vehicle.stop();
    }
}

That's a very good example to fix this problem.

But when I have the same problem but without those balises in the application context:

<context:component-scan></context:component-scan>
<context:annotation-config></context:annotation-config>

All the issues are solved by using the @Qualifier annotation, but in my case we don't use the balise that permit to use annotation.

The question is :

How can I fix this issue just using the configuration in application context, that's it, without using annotations?

I searched a lot and I found people talking about autowire attribute in the bean declaration <bean id="dao" class="package.IDao" autowire="byName"></bean> and I need more explanation about it.

like image 872
Med Elgarnaoui Avatar asked Apr 08 '19 11:04

Med Elgarnaoui


2 Answers

How can I fix this issue just using the configuration in application context?

You could use the qualifier tag like below (see https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers)

<context:annotation-config/>
  <beans>
    <bean class="your_pkg_route.Vehicle">
      <qualifier value="bike"/>
    </bean>
  </beans>
</context:annotation-config>

I found people talking about autowire attribute in the bean declaration and I need more explanation about it

Using Annotation

@Autowired used on a bean declaration method injects the defined dependencies by (another) declared beans. Now, if your dependencies are in the same context of your application, you don't need to use the @Autowired annotation at all because Spring is able to figure them out by itself. So, if your dependencies are outside your applicatoin context then you can use it.

For example, take as reference the below code:

@Autowired
@Bean
public MyBean getMybean(Dependency1 depdency1, Dependency2 depdency2) {
    return new MyBean(depdency1.getSomeStuff(), depdency2.getSomeOtherStuff());
}

Here, @Autowired will find an instance of Dependency1 and Dependency2 and will provide them for the creation of an instance of MyBean.

Using xml configuration

From Pro Spring 5... Spring supports five modes for autowiring.

  • byName: When using byName autowiring, Spring attempts to wire each property to a bean of the same name. So, if the target bean has a property named foo and a foo bean is defined in ApplicationContext, the foo bean is assigned to the foo property of the target.
  • byType: When using byType autowiring, Spring attempts to wire each of the properties on the target bean by automatically using a bean of the same type in ApplicationContext.
  • constructor: This functions just like byType wiring, except that it uses constructors rather than setters to perform the injection. Spring attempts to match the greatest numbers of arguments it can in the constructor. So, if your bean has two constructors, one that accepts a String and one that accepts String and an Integer, and you have both a String and an Integer bean in your ApplicationContext, Spring uses the two-argument constructor.
  • default: Spring will choose between the constructor and byType modes automatically. If your bean has a default (no-arguments) constructor, Spring uses byType; otherwise, it uses constructor.
  • no: This is the default

So, in your case you would need to do something like this (BUT, I would NOT recommend it. Why?, you would need to declare Vehicle class as a bean and a component which is not correct, see Spring: @Component versus @Bean. On the other hand I'm not sure if you could use it just declaring it as a bean):

// xml config
<context:annotation-config/>
  <beans>

    // use the primary tag here too! in order to say this the primary bean
    // this only works when there are only two implementations of the same interface
    <bean id="bike" primary="true" class="your_pkg_route.Bike"/>
    <bean id="car" class="your_pkg_route.Car"/>         

    <bean autowire="byName" class="your_pkg_route.VehicleService"/>

  <beans>
</context:annotation-config>

// VehicleService
@Component
public class VehicleService {

    private Vehicle bike;   // call attribute 'bike' so it is autowired by its name

    public void service() {
         //...
    }
}

As you can see there is a lot of complications trying to do this using xml config, so I would recommend you to use the annotation option if possible.

Related posts:

  • Why do I not need @Autowired on @Bean methods in a Spring configuration class?
  • Difference between @Bean and @Autowired

PS: I have not tested any of the posted codes.

like image 130
lealceldeiro Avatar answered Nov 01 '22 22:11

lealceldeiro


You can use @Primary instead of @Qualifier

@Primary
@Component(value="bike")
public class Bike implements Vehicle {

we use @Primary to give higher preference to a bean when there are multiple beans of the same type.

We can use @Primary directly on the beans

You can also set primary attribute in XML:

property has primary attribute:

<bean primary="true|false"/>

If a @Primary-annotated class is declared via XML, @Primary annotation metadata is ignored, and is respected instead.

like image 25
user7294900 Avatar answered Nov 01 '22 21:11

user7294900