将参考bean按类型自动连接到列表中


75

我有一类具有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在列表中自动自动连接所有类型的bean,而不是显式连接列表中的每个守护程序实现。我要解决的问题是,如果有人创建了Daemon类的新实现的bean,却忘记将其连接到列表中。

我已经在stackoverflow上的某个地方看到了这个问题,但无法再次找到它。对此表示歉意。



谢谢skaffmen。我将尝试了解此处涉及的概念。
RandomQuestion 2011年

Answers:


79

它应该像这样工作(从您的XML中删除ArrayList bean):

public Class Xyz {    

    private List<Daemon> daemons;

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

}

我认为没有办法用XML做到这一点。


参见: 3.9.2。@Autowired@Inject

通过将注释添加到需要该类型数组的字段或方法中,还可以从ApplicationContext提供特定类型的所有bean:

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

  // ...
}

顺便说一句,从Spring 4.x开始,这些列表可以使用@Ordered机制自动排序


7
谢谢肖恩。有效。我认为,添加@Autowired符号List<Daemons> daemons将使spring搜索类型为的bean java.util.List。令人惊讶的是,它如何找到列表中对象的类型并将其连接到列表中,最后将列表连接到主要对象中。
RandomQuestion 2011年

1
@al。没问题。我本人
肖恩·帕特里克·弗洛伊德

当自动装配“ List <Daemon>守护程序”时,Spring如何知道它应该寻找Daemon类型的bean,因为这是通用类型,并且在运行时不可用?
elyor

1
@elyor不太正确。对象可以擦除类型,而字段和方法则不受擦除。反射通过诸如Method.getGenericParameterTypes()之类的方法为您提供了方法。
肖恩·帕特里克·弗洛伊德

3

嗯,这可以通过Spring Documentation中所述的两种方法来实现。

以下是文档摘录。

使用byType或构造函数自动装配模式,您可以连接数组和类型化的集合。

1. autowire =“ byType”

如果xml中定义的bean的类型与list的类型匹配,则可以使用“ byType”进行自动装配。

例:

马达

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

电机1.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 =“ constructor”

如果在xml中定义的bean的类型与构造函数中的参数类型匹配,则可以使用“构造函数”进行自动装配。

例:

考虑上述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.

感谢你的回答。两种解决方案的问题:如果不在同一个spring.xml文件中定义“ electricMotor1”和“ electricMotor2” ...“ electricMotorN”,但共享同一ApplicationContext容器,是否可以正常工作?
梁军
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.