Сканирование компонентов весенней загрузки не распознает аннотацию квалификатора для разных bean-компонентов - PullRequest
0 голосов
/ 14 апреля 2020

Я заметил кое-что странное на примере использования шаблона проектирования Bridge при загрузке Spring. Чтобы преодолеть проблемы с наличием двух bean-компонентов одного типа в пути к классам, я использую аннотацию Qualifier. Однако по какой-то причине он не работает без использования подстановочного знака для сканирования компонентов.

Цвет. java

package com.example.bridge;

public interface Color {

  String fill();
}

Синий. 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";
  }
}

Красный. 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";
  }
}

Форма. java

package com.example.bridge;

public abstract class Shape {
  protected Color color;

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

  abstract public String draw();
}

Квадрат. 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.*", он будет работать, и приложение можно будет запустить. Технически, мне не нужно устанавливать подстановочный знак для базового пакета, и он должен рекурсивно собирать все компоненты. Кроме того, я не понимаю, в чем разница между "com.example.bridge.*" и "com.example.*".

1 Ответ

1 голос
/ 14 апреля 2020

Вы получили эту ошибку, потому что когда spring загружает контекст приложения, он обнаруживает, что Square - это bean-компонент Spring, и поэтому пытается внедрить Color. Поскольку он нашел 2impl, он генерирует ошибку.

Внедрение цвета работает только на контроллере, потому что вы указали точку впрыска -> @Autowired @Qualifier("Red") private Color red;

Когда вы запускаете тип Square вручную внутри контроллера Shape square = new Square(red); вам не нужны @Service типа Square

ОБНОВЛЕНО

Что касается сканирования пакетов, то это com.example.bridge и это com.example.bridge.** на самом деле то же самое.

...