Автоматичне підключення еталонних бобів до списку за типом


76

У мене є один клас, який має список об'єктів Daemonтипу.

class Xyz {    
    List<Daemon> daemons;
}

Моя весняна конфігурація виглядає так.

<bean id="xyz" class="package1.Xyz">
   <property name="daemons" ref="daemonsList">
</bean>

<bean id="daemon1" class="package1.DaemonImpl1"/>
<bean id="daemon2" class="package1.DaemonImpl2"/>

<bean id="daemonsList" class="java.util.ArrayList">
        <constructor-arg>
            <list>
                <ref bean="daemon1" />      
                <ref bean="daemon2" />
            </list>
        </constructor-arg>
</bean>

Тепер, замість явного підключення кожної реалізації демона у списку, чи можна автоматично підключати всі компоненти типу Daemonавтоматично до списку. Проблема, яку я намагаюся вирішити, полягає в тому, що якщо хтось створює компонент нової реалізації Daemonкласу і забуває включити його у список.

Я бачив це питання десь на stackoverflow, але не зміг знайти його знову. Вибачення за це.



Спасибі скефмени. Я спробував би зрозуміти поняття, яке тут задіяне.
RandomQuestion

Відповіді:


80

Він повинен працювати так (видаліть компонент ArrayList з вашого XML):

public Class Xyz {    

    private List<Daemon> daemons;

    @Autowired
    public void setDaemons(List<Daemon> daemons){
        this.daemons = daemons;
    }

}

Я не думаю, що існує спосіб зробити це в XML.


Див .: 3.9.2. @Autowiredі@Inject :

Також можна надати всі компоненти певного типу з ApplicationContext, додавши анотацію до поля або методу, який очікує масив цього типу:

public class MovieRecommender {

  @Autowired
  private MovieCatalog[] movieCatalogs;

  // ...
}

Те саме стосується набраних колекцій:

public class MovieRecommender {

  private Set<MovieCatalog> movieCatalogs;

  @Autowired
  // or if you don't want a setter, annotate the field
  public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
      this.movieCatalogs = movieCatalogs;
  }

  // ...
}

До речі, станом на весну 4.x ці списки можна впорядковувати автоматично за допомогою @Orderedмеханізму .


7
Дякую Шон. Це спрацювало. Я думав, додавання @Autowiredпозначень до List<Daemons> daemonsвесняного пошуку бобів, що мають тип java.util.List. Дивно, як він виявляє тип об’єктів у списку та підключає їх до списку і, нарешті, переводить список до основного об’єкта.
RandomQuestion

1
@al. без проблем. Я сам багато використовую цю функцію
Шон Патрік Флойд

Під час автоматичного підключення "Список <демона> демонів", звідки Spring знає, що він повинен шукати компоненти типу Daemon, оскільки це загальний тип і не буде доступний під час виконання?
elyor

1
@elyor це не зовсім правильно. Об’єкти стираються, а поля та методи - ні. Відображення дає вам засоби за допомогою таких методів, як Method.getGenericParameterTypes () .
Шон Патрік Флойд,

3

Ну, цього можна досягти двома способами, як зазначено у весняній документації .

Нижче наведено витяг з документації.

За допомогою режиму автоматичного підключення byType або конструктора ви можете підключати масиви та набрані колекції.

1. autowire = "byType"

Автопровід за допомогою "byType" можна досягти, якщо тип компонента, визначений у xml, відповідає типу списку.

Приклад:

Двигун.java

package com.chiranth;
public interface Motor 
{
   public void start();
}

ElectricMotor1.java

package com.chiranth;
public class ElectricMotor1 implements Motor
{
     public void start() 
     { 
         System.out.println("Motor 1 Started.");
     }
}

ElectricMotor2.java

package com.chiranth;
public class ElectricMotor2 implements Motor
{
    public void start() 
    {
        System.out.println("Motor 2 Started.");
    }
}

TeslaModelX.java

package com.chiranth;
import java.util.List;
public class TeslaModelX 
{
    private List<Motor> motor;

    public List<Motor> getMotor()
    {
        return motor;
    }

    public void setMotor(List<Motor> motor) 
    {
        this.motor = motor;
    }

    public void goForward()
    {
        for(Motor m :motor)
            m.start();
        System.out.println("Going Forward.");
    }
}

Spring.xml

<?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:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="electricMotor1" class="com.chiranth.ElectricMotor1"/>
    <bean id="electricMotor2" class="com.chiranth.ElectricMotor2"/>

    <bean id="modelX" class="com.chiranth.TeslaModelX" autowire="byType"/>
</beans>

Test.java

package com.chiranth;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test 
{
    public static void main(String[] args) 
    {
        ApplicationContext context= new ClassPathXmlApplicationContext("Spring.xml");
        TeslaModelX modelx=(TeslaModelX)context.getBean("modelX");
        modelx.goForward();
    }
}

ВИХІД:

Motor 1 Started.
Motor 2 Started.
Going Forward.

2. autowire = "конструктор"

Автопровід за допомогою "конструктора" можна досягти, якщо тип компонента, визначений у xml, відповідає типу аргументу в конструкторі.

Приклад:

Враховуючи вищезазначені Motor.java, ElectricMotor1.java та ElectricMotor2.java.

TeslaModelX.java

package com.chiranth;
import java.util.List;
public class TeslaModelX 
{
    private List<Motor> motor;

    public TeslaModelX(List<Motor> motor)
    {
        this.motor=motor;
    }

    public void goForward()
    {
        for(Motor m:motor)
            m.start();
        System.out.println("Going Forward.");
    }
}

Spring.xml

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xmlns:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="electricMotor1" class="com.chiranth.ElectricMotor1"/>
    <bean id="electricMotor2" class="com.chiranth.ElectricMotor2"/>

    <bean id="modelX" class="com.chiranth.TeslaModelX" autowire="constructor"/>
</beans>

Test.java

package com.chiranth;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test 
{
    public static void main(String[] args) 
    {
        ApplicationContext context= new ClassPathXmlApplicationContext("Spring.xml");
        TeslaModelX modelX=(TeslaModelX)context.getBean("modelX");
        modelX.goForward();
    }
}

ВИХІД:

Motor 1 Started.
Motor 2 Started.
Going Forward.

Дякую за відповідь. Питання для будь-якого з рішень: чи це спрацює, якщо "electricMotor1" та "electricMotor2" ... "electricMotorN" визначені не в одному файлі spring.xml, а мають один і той же контейнер ApplicationContext?
Лянг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.