如何在不定义每个 bean 的情况下创建多个相同类型的 Spring 个 bean

How do I create multiple Spring beans of the same type without defining each one

我已经看到很多关于我尝试使用 BeanDefinitionRegistryPostProcessor 做的事情的解决方法,但我想知道是否有一种方法可以直接进入 Spring创建 bean API 以覆盖某些行为。

我想看到的是这样的(注意@Components中的's'):

@Components(prefix="myBean-", numberOfInstances="${myapp.mybean.numberOfInstances}")
public class MyBean {

  private final MyService myService;

  public MyBean(final MyService myService) {
    this.myService = myService;
  }

  @Scheduled(fixedDelayString = "${myapp.mybean.fixedDelay}")
  public myJob() {
    System.out.println("I'm working!");
  }
}

我基本上是在寻找与 @Component 相同的功能,我可以在其中指定要创建的实例数量,并且只生成名称。

正如我之前提到的,我发现做这种事情的唯一方法(现在专门针对计划任务)是使用 BeanDefinitionRegistryPostProcessor 创建实例或创建自定义 SchedulingConfigurer 在不使用 Spring beans 的情况下手动配置任务,这意味着所有 Runnable 的依赖项都必须连接到 SchedulingConfigurer,这感觉很脏。

这是否可能——添加一个新注释来扫描并调用其他方式来创建 bean?

更新

感谢@vince 帮助我意识到我不需要为每项工作都使用单独的 bean;我只需要多次将单例配置到 FixedDelayTask.

@Component
public class MyBean {

  private final MyService myService;

  public MyBean(final MyService myService) {
    this.myService = myService;
  }

  // Remove @Scheduled here since we have to configure multiple
  // instances manually. This is where it would be nice to specify
  // how many jobs of the same type you want.
  // @Scheduled(fixedDelayString = "${myapp.mybean.fixedDelay}")
  public myJob() {
    System.out.println("I'm working!");
  }
}

@Configuration
@EnableScheduling
public class MyBeanTaskConfiguration implements SchedulingConfigurer {

  private final MyBean myBean;

  public MyBeanTaskConfiguration(MyBean myBean) {
    this.myBean = myBean;
  }

  @Override
  public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
    for (int i = 0; i < numberOfWorkers; i++) {
      taskRegistrar.scheduleFixedDelayTask(
              new FixedDelayTask(
                      myBean,
                      repeatIntervalMs,
                      repeatIntervalMs / numberOfWorkers * i + startDelayMs
              )
      );
    }
  }

}

其实我想知道你为什么要这样做。按照IOC的理念,bean应该委托给容器,客户端不需要关心bean的生命周期。这就是为什么 Spring 提供 @Scope 来支持不同的 bean 作用域,例如 singleton/request/session。所以我不认为控制某个bean的具体数量是个好办法,而且bean理论上应该是non-stateful,所以单个实例就足够了。

原型作用域 bean 将作为新实例提供给容器的每个请求。

@Component
@Scope("prototype")
public class MyBean {

  private final MyService myService;
  public MyBean(final MyService myService) {
    this.myService = myService;
  }

  // ...
}

// Get two separate instances
MyBean bean1 = (MyBean)applicationContext.getBean("myBean");
MyBean bean2 = (MyBean)applicationContext.getBean("myBean");