【问题标题】:Spring Java Config - exposing bean using InterfaceSpring Java Config - 使用接口公开 bean
【发布时间】:2015-11-24 21:54:16
【问题描述】:

我有一个类,比如说“DefaultService”,它实现了两个接口:“Service1”和“Service2”。 Spring java 配置如下所示:

@Bean
Service1 defaultService() {
    return new DefaultService();
}

现在,我有另一个需要 'Service2' 的 bean Foo。

public class Foo implements AnotherInterface {
   @Autowired
   private Service2 service2;
}

这个 bean 也是通过 Java config 配置的:

@Bean
AnotherInterface anotherInterface(){
   return new Foo();
}

Spring 不喜欢这种配置。我认为这是有道理的,因为“DefaultService”被公开为“Service1”,而不是“Service2”(Foo 需要)。

No qualifying bean of type [...Service2] found for dependency: expected at least 1 bean which qualifies ...

当然,我可以将 DefaultService 公开为 Service2。但是如果有另一个 bean 需要 Service1 怎么办?对于这种情况,Spring 的建议是什么?我发现的另一个(奇怪)问题是以下配置有效:

@Bean
Service2 defaultService(){ // exposing the bean as Service2, to fix dependency on Foo
   return new DefaultService(); 
}

@Bean
AnotherDependant anotherDependant(Service1 service1){
   return new AnotherDependant(service1);
}

Spring 如何将 Service1 连接到“AnotherDependant”的配置声明(我在第一个场景中对 @Autowired 不满意)? 我正在使用 Spring 3.2.2.RELEASE,虽然我怀疑版本真的很重要..

我最好的解决方法是:

@Bean
DefaultService defaultService(){
return new DefaultService();
}

@Bean
Service1 service1(){
return defaultService();
}

@Bean
Service2 service2(){
return defaultService();
}

但这很丑……

================================================ ========================= 回复@Oskar。 基本上@Oskar 的建议与在 xml 中声明两个相同。即在 spring 容器中创建同一类的两个实例。

public interface Driveable {}
public interface Vehicle {}
public class Car implements Vehicle, Driveable{}


@Configuration
public class Config {
    @Bean
    public Vehicle vehicle() {
        return new Car();
    }
    @Bean
    public Driveable driveable() {
        return new Car();
    }
}

public class Main {
    public static void main(String[] args) {
        final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

        final Driveable driveable = context.getBean("driveable", Driveable.class);
        final Vehicle vehicle = context.getBean("vehicle", Vehicle.class);
        System.out.println(driveable == vehicle);
    }
}

【问题讨论】:

  • 当然是因为 java config 和 xml config 是相等的 ;) 更何况你在这里明确声明了两个不同的对象,final Driveable driveable = context.getBean("driveable", Driveable.class); 如果你声明两次,你也会得到两个对象,你可以得到一个 bean然后将其转换到另一个界面,但这真的很难看

标签: spring dependency-injection spring-java-config


【解决方案1】:
public interface Driveable {}
public interface Vehicle {}

@Component
public class Car implements Vehicle, Driveable{}


@Configuration
public class Config {

    @Autowired
    private Car car;

    @Bean
    public Vehicle vehicle() {
        return car;
    }

    @Bean
    public Driveable driveable() {
        return car;
    }
}

public class Application {

    public static void main(String[] args) throws Exception {
        final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class, Car.class);
        final Driveable driveable = context.getBean("driveable", Driveable.class);
        final Vehicle vehicle = context.getBean("vehicle", Vehicle.class);
        System.out.println(driveable == vehicle);
    }

}

以问题中的汽车为例,

  1. 将 Car 定义为 @Component。
  2. 在自动装配的 Config 中声明一个字段 Car car
  3. 使用自动装配字段从两个 @Bean 注释方法返回。

如果我们使用@ComponentScan,Car 组件将被自动拾取。否则,如果我们自己创建上下文,我们可以在 AnnotationConfigApplicationContext 构造函数中传递 Car 类(如代码所示)。

【讨论】:

  • 你的实现有错别字,return new car,如果没有@ComponentScan,你想如何获得@Component
  • @Oskar:更正了错字。可以通过 AnnotationConfigApplicationContext 在其构造函数中提供的类上扫描组件。
  • 我现在看到了,因为您刚刚编辑了带有主要实现的帖子,但是像这样明确声明每个类会使您的构造函数变得非常庞大和混乱
  • 是的,我同意。如果您不想使用@ComponentScan,那将是一个问题。
  • 我已经删除了我的答案,我猜你的答案更好,但是 IMO 最好为具有相同实现的不同接口声明两个 @Bean,因为你不能设置不同的 bean 范围,否则它总是取决于@Autowired 范围
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-14
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 1970-01-01
  • 2021-08-27
  • 1970-01-01
相关资源
最近更新 更多