【问题标题】:Spring boot component scan does not recognize qualifier annotation for different beansSpring Boot 组件扫描无法识别不同 bean 的限定符注释
【发布时间】:2020-04-14 10:58:56
【问题描述】:

我注意到在 Spring boot 中使用 Bridge 设计模式的例子有些奇怪。为了克服在类路径中有两个相同类型的 bean 的问题,我使用了 Qualifier 注释。但是,由于某种原因,如果不使用通配符进行组件扫描,它就无法工作。

颜色.java

package com.example.bridge;

public interface Color {

  String fill();
}

Blue.java

package com.example.bridge;

import org.springframework.stereotype.Service;

@Service("Blue")
public class Blue implements Color {
  @Override
  public String fill() {
    return "Color is Blue";
  }
}

Red.java

package com.example.bridge;

import org.springframework.stereotype.Service;

@Service("Red")
public class Red implements Color {
  @Override
  public String fill() {
    return "Color is Red";
  }
}

Shape.java

package com.example.bridge;

public abstract class Shape {
  protected Color color;

  public Shape(Color color){
    this.color = color;
  }

  abstract public String draw();
}

Square.java

package com.example.bridge;

import org.springframework.stereotype.Service;

@Service
public class Square extends Shape {

  public Square(Color color) {
    super(color);
  }

  @Override
  public String draw() {
    return "Square drawn. " + color.fill();
  }
}

三角形.java

package com.example.bridge;

@Service
public class Triangle extends Shape {

  public Triangle(Color color) {
    super(color);
  }

  @Override
  public String draw() {
    return "Triangle drawn. " + color.fill();
  }
}

BridgeApplication.java

package com.example.bridge;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.example.bridge")
public class BridgeApplication {
  public static void main(String[] args) {
    SpringApplication.run(BridgeApplication.class, args);
  }
}

控制器:

package com.example.bridge;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BridgeController {

  @Autowired
  @Qualifier("Red")
  private Color red;

  @GetMapping("/red")
  @ResponseStatus(HttpStatus.OK)
  public String redSquare() {
    Shape square = new Square(red);
    return square.draw();
  }

}

此项目启动失败,出现以下异常:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-04-14 20:52:52.839 ERROR 9689 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.example.bridge.Square required a single bean, but 2 were found:
    - Blue: defined in file [IdeaProjects/test-bridge-design/target/classes/com/example/bridge/Blue.class]
    - Red: defined in file [IdeaProjects/test-bridge-design/target/classes/com/example/bridge/Red.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

好的,现在让我们将组件扫描的基本包更改为使用"com.example.*"。同样的问题。

现在,如果我将基本包更改为"com.example.bridge.*",它可以工作并且可以启动应用程序。从技术上讲,我不需要为基本包设置通配符,它​​应该递归地获取所有 bean。另外,我不明白"com.example.bridge.*""com.example.*" 之间的区别是什么。

【问题讨论】:

  • 您说它有效...但是Square 中注入了哪种颜色?我在您的代码中没有看到任何主要或限定符...
  • @CodeScale 我已经添加了控制器部分。在这种情况下,它会按预期返回红色方块。
  • 我不明白你为什么将Square 定义为spring bean et init这个类型在控制器中手动Shape square = new Square(red);这样Square不需要是spring bean...

标签: java spring spring-boot dependency-injection


【解决方案1】:

您收到此错误是因为当 spring 加载应用程序上下文时,它发现 Square 是一个 spring bean,因此尝试注入一个 Color。当它发现 2impl 时,它会产生一个错误。

颜色的注入仅在控制器上起作用,因为您限定了注入点 -> @Autowired @Qualifier("Red") private Color red;

当您在控制器Shape square = new Square(red); 中手动初始化Square 类型时,您不需要Square 类型上的@Service

更新

关于包扫描这个com.example.bridge和这个com.example.bridge.**实际上是一样的。

【讨论】:

  • 实际上,手动初始化是我试图理解为什么会出现这个问题的尝试的遗留物。否则,你是对的,在这种情况下不需要注射。无论对象是如何初始化的,只有当组件扫描将基本包称为“com.example.bridge.*”时,应用程序才有效
  • 刚刚更新了我的答案。但是按原样不起作用是正常的,因为您在方形类型上没有@Qualifier...这里不是组件扫描的问题。
  • 没错,“com.example.bridge”和“com.example.bridge.*”应该是一样的,但是在这个例子中“com.example.bridge.*”出于某种原因只工作。此外,关于错误,它实际上抱怨 Square 的构造函数接受一种颜色。它抱怨有两个 Color 类型的 bean,并且在 Square 初始化时无法区分它们。那你是说解决这个问题的唯一办法就是手动初始化Square,Square根本无法注入?
  • 您有 2 个解决方案.... 要么注入 Square,但您必须在其中注入合格的 Color(红色或蓝色 impl)。但我认为这不是GOF Bridge pattern 的想法。或者您在控制器中注入颜色并手动创建正方形。所以你可以用任何颜色创建正方形。最后一个选项是创建类RedSquareBlueSquare 并将对应的Color 和对应的@Qualifier 注入其中...但是最后一个选项不符合bridge pattern,因为类的爆炸...跨度>
猜你喜欢
  • 2012-09-03
  • 2015-01-10
  • 1970-01-01
  • 2022-12-19
  • 2014-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多