Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring: Xml based Autowiring a list of beans by interface type

With Spring it is possible to inject a list of beans by the interface class like:

@Component
public class Service {
  @Autowire
  private List<InterfaceType> implementingBeans;
  ...
}

All defined beans that implement this interface will be present in this List.

The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.

I need to use this mechanism from outside via xml configuration.

<bean id="service" class="...Service">
  <property name="implementingBeans">
    ??? tell spring to create a list bean that resolves all beans of the interfaceType.
  </property>
</bean>

Does anyone know how to solve this?

EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.

I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.

Kind regards.

like image 622
serprime Avatar asked Oct 21 '22 17:10

serprime


1 Answers

An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".

Controls whether bean properties are "autowired". This is an automagical process in which bean references don't need to be coded explicitly in the XML bean definition file, but rather the Spring container works out dependencies.
[...]

  1. "byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is raised, and you cannot use byType autowiring for that bean. If there is none, nothing special happens.

The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.

Your XML would simply look like

<bean id="service" class="...Service" autowire="byType">
</bean>

My original suggested solution made use of SpEL.

In the module that does have Spring dependencies, create a DTO

@Component(value = "beanDTO")
public class BeanDTO {
    @Autowire
    private List<InterfaceType> implementingBeans;

    public List<InterfaceType> getImplementingBeans() {
        return implementingBeans;
    }
}

and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.

<bean id="service" depends-on="beanDTO" class="...Service">
    <property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>

Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.


Following comments on question:

In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with @javax.inject.Inject instead of @Autowired. Similarly, you can use @Named instead of @Component. The documentation has more details.

like image 51
Sotirios Delimanolis Avatar answered Oct 23 '22 09:10

Sotirios Delimanolis