按类型自动将引用 bean 连接到列表中

我有一个类,它有一个 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>

现在不需要在 list 中显式连接每个守护进程实现,而是可以在 list 中自动连接所有 Daemon类型的 bean。我试图解决的问题是,如果有人创建了一个新实现的 Daemon类的 bean,并忘记将其连接到 list 中。

我在堆栈溢出的某个地方看到过这个问题,但是不能再次找到它。对此表示歉意。

79117 次浏览

It should work like this (remove the ArrayList bean from your XML):

public Class Xyz {


private List<Daemon> daemons;


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


}

I don't think there's a way to do this in XML.


See: 3.9.2. @Autowired and @Inject:

It is also possible to provide all beans of a particular type from the ApplicationContext by adding the annotation to a field or method that expects an array of that type:

public class MovieRecommender {


@Autowired
private MovieCatalog[] movieCatalogs;


// ...
}

The same applies for typed collections:

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


// ...
}

BTW, as of Spring 4.x, these lists can be ordered automatically using the @Ordered mechanism.

Well, this can be achieved in two ways as stated in Spring Documentation.

Below is the excerpt from the documentation.

With byType or constructor autowiring mode, you can wire arrays and typed collections.

1. autowire="byType"

Autowiring using "byType" can be achieved if the type of the bean defined in the xml matches the type of list.

Example:

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

OUTPUT:

Motor 1 Started.
Motor 2 Started.
Going Forward.

2. autowire="constructor"

Autowiring using "constructor" can be achieved if the type of the bean defined in the xml matches the type of the argument in the constructor.

Example:

Considering the above Motor.java , ElectricMotor1.java and 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();
}
}

OUTPUT:

Motor 1 Started.
Motor 2 Started.
Going Forward.