简体   繁体   中英

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

I've seen a lot of workaround-looking things regarding what I'm trying to do using BeanDefinitionRegistryPostProcessor , but I wondered if there was a way to tap directly into Spring's bean creation API to override some behavior.

What I would like to see is something like this (note the 's' in @Components ):

@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!");
  }
}

I am basically looking for the same functionality of @Component where I can specify how many instances to make and just have the name generated.

As I mentioned before, the only way I have found to do this sort of thing (specifically for scheduled tasks now) is to use the BeanDefinitionRegistryPostProcessor to create the instances or create a custom SchedulingConfigurer to configure the tasks manually without using Spring beans, which means all the Runnable 's dependencies have to be wired into the SchedulingConfigurer , and that just feels dirty.

Is this even possible--to add a new annotation to scan for and invoke some other way to create the beans?

Update

Thanks to @vince for helping me realize I don't need a separete bean for each job; I just have to configure the singleton multiple times into the 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
              )
      );
    }
  }

}

Actually I'm wondering why u wanna do this. According to the IOC philosophy, beans should be delegated to container and clients don't need to care about beans' lifecycles. That's why Spring provides @Scope to support different bean scopes like singleton/request/session. So I don't think it a good way to control the specific number of a certain bean, besides, beans should theoretically be non-stateful, thus a single instance is fairly enough.

Prototype scoped beans will be provided as a new instance for each request to the container.

@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");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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