在注释驱动的上下文中自动装配bean

时间:2014-01-24 18:40:09

标签: java spring

Usercase:

我们得到了一堆自动装配的bean,每个bean都注明了@Service,比如B1,B2和B3,它们具有相同的接口BInterface。

在A类的方法中,我需要根据键字符串通过接口使用其中一个,比如“b1”,“b2”和“b3”。

我可以使用hashmap Key - > BInterface,但我感兴趣的是任何Spring优雅(成语)方式来动态注入我需要的bean。我也知道getBean被认为是一种反模式。

我不知道它是否重要,但上下文定义为注释驱动。

4 个答案:

答案 0 :(得分:1)

执行此操作的Spring方法是让您的三个bean实现三个不同的接口(或子接口),然后使用@Autowired注释引用这三个接口。毕竟,如果三个bean具有不同的功能,那么这样做是有意义的。

你也可以拥有一个包含三个的bean,并且有@Autowired,所以你不需要三个引用。

如果有更多相同接口的实例,我甚至不确定@Service如何正确连线。它适用于具体的类,但我认为它不适用于许多接口的实现。

以下是我建议的一个例子:

interface BInterface{ /*...*/ }

@Service
class B1 extends BInterface{/*...*/}

@Service
class B2 extends BInterface{/*...*/}

@Service
class B3 extends BInterface{/*...*/}

@Service
class BProvider {
  @Autowired
  private B1 b1;
  @Autowired
  private B2 b2;
  @Autowired
  private B2 b2;
  public BInterface get(String k) {
    switch(k){
      case "b1": return b1;
      case "b2": return b2;
      case "b3": return b3;
      default: return b1;
    }
  }
}

BClient {
  @Autowired
  private BProvider provider;
  public void doSomething(){
    BInterface b = provider.get(/* one of the three */);
    // use b ...
  }
}

作为替代方案,您可以使BProvider可配置,并使用XML配置使用Map<String,BInterface>进行配置。

所以它会是:

@Service
class BProvider {
  @Autowired
  private Map<String,BInterface> bs;

  public BInterface get(String k) {
    return bs.get(k);
  }
}

您必须在配置文件中定义您的地图。为此,您可以在XML文件中手动创建bean,或者我相信您可以使用BeanPostProcessor将它们添加到集合中。

答案 1 :(得分:1)

我不确定你是否有xml配置。但你可以通过名字自动装配。在spring配置中定义3个bean b1,b2,b3,并为类中的bean名称设置setter方法

<beans>
...
    <bean name="b1" class="some.package.B1" />
    <bean name="b2" class="some.package.B2" />
    <bean name="b3" class="some.package.B3" />
...
</beans>


Class UserOfBInterface{
BInterface b1;
BInterface b2;
BInterface b3;

public void setB1(BInterface b1){
this.b1 = b1;
}

public void setB2(BInterface b2){
this.b2 = b2;
}

public void setB3(BInterface b3){
this.b3 = b3;
}
}

另一种方法是使用@Qualifier注释而不是使用setter注入。

答案 2 :(得分:1)

您应该能够使用@Resource注释来按名称获取资源:

@Resource(name = "b1")
BInterface b1

@Resource(name = "b2")
BInterface b2

@Resource(name = "b3")
BInterface b3

答案 3 :(得分:1)

这是我能想到的最干净的方式,它确实依赖于getBeansOfType(),但只在@Configuration中运行一次,而不是在运行时“依赖项”解析它们自己的依赖项。

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DefaultDatabaseConfiguration {

    @Autowired private ApplicationContext applicationContext;

    @Bean
    public Map<String, MyService> services() {
        return applicationContext.getBeansOfType(MyService.class);
    }
}