Autowire-Referenz-Beans werden nach Typ in die Liste aufgenommen

75

Ich habe eine Klasse, die eine Liste von Objekten vom DaemonTyp hat.

class Xyz {    
    List<Daemon> daemons;
}

Meine Federkonfiguration sieht so aus.

<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>

Anstatt jede Daemon-Implementierung explizit in der Liste zu verkabeln, ist es jetzt möglich, alle Beans des Typs Daemonautomatisch in der Liste automatisch zu verdrahten . Das Problem, das ich zu lösen versuche, ist, wenn jemand eine Bean der neuen Implementierung der DaemonKlasse erstellt und vergisst, sie in eine Liste einzubinden.

Ich habe diese Frage irgendwo im Stackoverflow gesehen, kann sie aber nicht wiederfinden. Entschuldigung dafür.

Zufällige Frage
quelle
Danke Skaffmen. Ich würde versuchen, das Konzept hier zu verstehen.
RandomQuestion

Antworten:

79

Es sollte so funktionieren (entfernen Sie die ArrayList-Bean aus Ihrem XML):

public Class Xyz {    

    private List<Daemon> daemons;

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

}

Ich glaube nicht, dass es eine Möglichkeit gibt, dies in XML zu tun.


Siehe: 3.9.2. @Autowiredund@Inject :

Es ist auch möglich, alle Beans eines bestimmten Typs aus dem ApplicationContext bereitzustellen, indem die Anmerkung zu einem Feld oder einer Methode hinzugefügt wird, die ein Array dieses Typs erwartet:

public class MovieRecommender {

  @Autowired
  private MovieCatalog[] movieCatalogs;

  // ...
}

Gleiches gilt für typisierte Sammlungen:

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;
  }

  // ...
}

Übrigens können diese Listen ab@Ordered Spring 4.x automatisch über den Mechanismus bestellt werden .

Sean Patrick Floyd
quelle
7
Danke Sean. Es funktionierte. Ich dachte, das Hinzufügen einer @AutowiredNotation List<Daemons> daemonswürde die Frühlingssuche nach Bohnen vom Typ machen java.util.List. Es ist erstaunlich, wie es die Art der Objekte in der Liste herausfindet und sie in die Liste und schließlich die Liste in das Hauptobjekt verdrahtet.
RandomQuestion
1
@al. kein Problem. Ich benutze diese Funktion selbst sehr oft
Sean Patrick Floyd
Woher weiß Spring beim automatischen Verdrahten von "List <Daemon> -Dämonen", dass nach Beans vom Typ Daemon gesucht werden sollte, da dies ein generischer Typ ist und zur Laufzeit nicht verfügbar ist?
Elyor
1
@elyor das ist nicht ganz richtig. Objekte können gelöscht werden, Felder und Methoden nicht. Reflexion gibt Ihnen die Mittel durch Methoden wie Method.getGenericParameterTypes () .
Sean Patrick Floyd
3

Nun, dies kann auf zwei Arten erreicht werden, wie in der Frühjahrsdokumentation angegeben .

Unten finden Sie den Auszug aus der Dokumentation.

Im automatischen Drahtmodus byType oder Konstruktor können Sie Arrays und typisierte Sammlungen verkabeln.

1. autowire = "byType"

Autowiring mit "byType" kann erreicht werden, wenn der in der XML definierte Bean-Typ mit dem Listentyp übereinstimmt.

Beispiel:

Motor.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();
    }
}

AUSGABE:

Motor 1 Started.
Motor 2 Started.
Going Forward.

2. autowire = "Konstruktor"

Autowiring mit "Konstruktor" kann erreicht werden, wenn der Typ der in der XML definierten Bean mit dem Typ des Arguments im Konstruktor übereinstimmt.

Beispiel:

In Anbetracht der oben genannten Motor.java, ElectricMotor1.java und 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();
    }
}

AUSGABE:

Motor 1 Started.
Motor 2 Started.
Going Forward.
Chiranth
quelle
Danke für die Antwort. Frage für beide Lösungen: Würde dies funktionieren, wenn "electricMotor1" und "electricMotor2" ... "electricMotorN" nicht in derselben spring.xml-Datei definiert sind, sondern denselben ApplicationContext-Container verwenden?
Liang