简体   繁体   English

Spring 启动组件扫描无法识别不同 bean 的限定符注释

[英]Spring boot component scan does not recognize qualifier annotation for different beans

I have been noticing something weird with the example of using the Bridge design pattern with Spring boot.在使用带有 Spring 引导的桥设计模式的示例中,我注意到了一些奇怪的事情。 To overcome the issues of having two beans of the same type in the classpath, I am using Qualifier annotation.为了克服在类路径中有两个相同类型的 bean 的问题,我使用了 Qualifier 注释。 However, for some reason, it does not work without using a wildcard for component scan.但是,由于某种原因,如果不使用通配符进行组件扫描,它就无法工作。

Color.java颜色.java

package com.example.bridge;

public interface Color {

  String fill();
}

Blue.java蓝色.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红色.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形状.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方形.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();
  }
}

Triangle.java三角.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 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);
  }
}

Controller: Controller:

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

}

This project fails to start with the following exception:此项目无法启动,出现以下异常:

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

Ok, now let's change the base package for the component scan to use "com.example.*" .好的,现在让我们将组件扫描的基础 package 更改为使用"com.example.*" The same issue.同样的问题。

Now, if I change the base package to be "com.example.bridge.*" it works and the application can be started.现在,如果我将基础 package 更改为"com.example.bridge.*" ,它可以工作并且可以启动应用程序。 Technically, I don't need to set the wildcard for the base package and it should pick up all the beans recursively.从技术上讲,我不需要为基础 package 设置通配符,它应该递归地获取所有 bean。 Also, I don't understand what the difference between "com.example.bridge.*" and "com.example.*" is.另外,我不明白"com.example.bridge.*""com.example.*"之间的区别是什么。

You got this error because when spring loads the application context it finds that Square is a spring bean and so tries to inject a Color.您收到此错误是因为当 spring 加载应用程序上下文时,它发现Square是 spring bean,因此尝试注入颜色。 As it found 2impl it generates an error.当它发现 2impl 时,它会产生一个错误。

The injection of color is only working on controller because you qualified the injection point -> @Autowired @Qualifier("Red") private Color red;颜色的注入仅适用于 controller 因为您限定了注入点 -> @Autowired @Qualifier("Red") private Color red;

As you init the Square type manually inside the controller Shape square = new Square(red);当您在 controller 中手动初始化Square类型时, Shape square = new Square(red); you don't need the @Service on the Square type您不需要Square类型的@Service

UPDATED更新

Concerning package-scan this com.example.bridge and this com.example.bridge.** are actually the same.关于包扫描这个com.example.bridge和这个com.example.bridge.**实际上是相同的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM