如何在不定义每个 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");
我已经看到很多关于我尝试使用 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");