有什么方法可以知道在 Spring 中使用来自父 class 的 bean 吗?

Is there any way to know in Spring what bean to use while being from the parent class?

我有这个特定问题,我无法使用 @Qualifier,因为我需要父 class 中的 bean。我的想法是删除 baseComponent 属性并在 BaseController 中创建一个抽象方法,例如 getComponent() 和 return BaseComponent 所需的 bean ... 但也许有是通过配置执行此操作的更简洁的方法。

@RestController
public abstract class BaseController {

    @Autowired
    private BaseComponent baseComponent;

    @GetMapping("/something")
    public void doSomething() {
        baseComponent.printSomething();
    }

}

@RestController
@RequestMapping(value = "/foo")
public class FooController extends BaseController {

}

@RestController
@RequestMapping(value = "/bar")
public class BarController extends BaseController {

}

public interface BaseComponent {
    void printSomething();
}

@Component
public class FooComponent implements BaseComponent {

    @Override
    public void printSomething() {
        System.out.println("foo!");
    }

}

@Component
public class BarComponent implements BaseComponent{

    @Override
    public void printSomething() {
        System.out.println("bar!");
    }

}

您可以通过以下方式进行

import org.springframework.beans.factory.BeanFactory;

@RestController
public abstract class BaseController {

    @Autowired
    private BeanFactory beanFactory;

    @GetMapping("/something")
    public void doSomething() {
        BaseComponent baseComponent = beanFactory.getBean("Foo", // or "Bar"
                                                          BaseComponent.class); 
        baseComponent.printSomething();
    }

}


@Component("Foo")
public class FooComponent implements BaseComponent {
...

}


@Component("Bar")
public class BarComponent implements BaseComponent{
...

}

如果我没看错的话。

这是我不喜欢直接自动装配到私有字段的原因之一。我会通过 BaseController 的构造函数注入 BaseComponent 来做到这一点:

public abstract class BaseController {

   private final BaseComponent baseComponent;

   protected BaseController(BaseComponent baseComponent){
       this.baseComponent = baseComponent;
   }

   @GetMapping("/something")
   public ResponseEntity<String> getSomething(){
       return new ResponseEntity<String>(baseComponent.getSomething(), HttpStatus.OK);
   }
}

@RestController
@RequestMapping("/foo")
public class FooController extends BaseController{

   @Autowired
   public FooController(@Qualifier("fooComponent") BaseComponent baseComponent) {
      super(baseComponent);
   }
}

@RestController
@RequestMapping("/bar")
public class BarController extends BaseController{

   @Autowired
   public BarController(@Qualifier("barComponent") BaseComponent baseComponent){
       super(baseComponent);
   }
}

@Component
public class BarComponent implements BaseComponent {

   @Override
   public String getSomething() {
       return "bar";
   }
}

@Component
public class FooComponent implements BaseComponent {

   @Override
   public String getSomething() {
     return "foo";
   }
}

对 /something/bar 的请求将 return bar 而对 something/foo 的请求将 return foo.

请注意,抽象 BaseComponent 实际上并未声明为任何类型的 Spring 组件,也没有自动注入任何依赖项。相反,sub类 是组件,依赖项被连接到它们的构造函数中并通过 super 传递到 BaseComponent。子类构造函数为 @Qualifier 注释提供了一个位置来指定您想要的 BaseComponent

理论上,我不喜欢声明两个 类 除了注释之外完全相同。但在实践中,我发现有时仅声明 类 来保存 Spring 注释是最简单的。这比以前的 XML 配置要好。

如果不想硬编码 bean 名称,可以使用泛型:

@RestController
public abstract class BaseController<T extends BaseComponent> {

   @Autowired
   private T baseComponent;

   ...

}

@RestController
public class FooController extends BaseController<FooComponent> {
 ...
}