如何以动态方式创建Spring Beans。使用Quartz SchedulerFactoryBean [英] How to create Spring Beans in a dynamical way. Using Quartz SchedulerFactoryBean
问题描述
我有一个 QuartzJobConfig
类,我注册了我的 Spring-Quartz-Beans
。
I have a QuartzJobConfig
class where I register my Spring-Quartz-Beans
.
我按照 SchedulerFactoryBean的指示
, JobDetailFactoryBean
和 CronTriggerFactoryBean
。
我的作业配置为 yaml
文件在应用程序之外。意味着我必须在应用程序启动时动态创建Bean。
My Jobs are configured in a yaml
file outside the application. Means I have to create the Beans dynamically when the application starts.
我的配置:
channelPartnerConfiguration:
channelPartners:
- code: Job1
jobConfigs:
- schedule: 0 * * ? * MON-FRI
name: Job1 daily
hotel: false
allotment: true
enabled: true
- schedule: 30 * * ? * MON-FRI
name: Job2 weekly
hotel: true
allotment: false
enabled: true
...
我的配置类:
@Configuration
public class QuartzJobConfig implements IJobClass{
@Autowired
ChannelPartnerProperties channelPartnerProperties;
@Autowired
private ApplicationContext applicationContext;
@Bean
public SchedulerFactoryBean quartzScheduler() {
SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();
quartzScheduler.setOverwriteExistingJobs(true);
quartzScheduler.setSchedulerName("-scheduler");
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
quartzScheduler.setJobFactory(jobFactory);
// point 1
List<Trigger> triggers = new ArrayList<>();
for(ChannelPartner ch : channelPartnerProperties.getChannelPartners()){
for(JobConfig jobConfig : ch.getJobConfigs()){
triggers.add(jobTrigger(ch, jobConfig).getObject());
}
}
quartzScheduler.setTriggers(triggers.stream().toArray(Trigger[]::new));
return quartzScheduler;
}
@Bean
public JobDetailFactoryBean jobBean(ChannelPartner ch, JobConfig jobConfig) {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobClass(findJobByConfig(jobConfig));
jobDetailFactoryBean.setGroup("mainGroup");
jobDetailFactoryBean.setName(jobConfig.getName());
jobDetailFactoryBean.setBeanName(jobConfig.getName());
jobDetailFactoryBean.getJobDataMap().put("channelPartner", ch);
return jobDetailFactoryBean;
}
@Bean
public CronTriggerFactoryBean jobTrigger(ChannelPartner ch, JobConfig jobConfig) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(jobBean(ch, jobConfig).getObject());
cronTriggerFactoryBean.setCronExpression(jobConfig.getSchedule());
cronTriggerFactoryBean.setGroup("mainGroup");
return cronTriggerFactoryBean;
}
@Override
public Class<? extends Job> findJobByConfig(JobConfig jobConfig) {
if(isAllotmentJob(jobConfig) && isHotelJob(jobConfig)){
return HotelAndAllotmentJob.class;
}
if(isAllotmentJob(jobConfig)){
return AllotmentJob.class;
}
if(isHotelJob(jobConfig)){
return HotelJob.class;
}
return HotelAndAllotmentJob.class;
}
private boolean isAllotmentJob(JobConfig jobConfig){
return jobConfig.isAllotment();
}
private boolean isHotelJob(JobConfig jobConfig) {
return jobConfig.isHotel();
}
}
我的问题是创建迭代中的Bean(第1点)只做了一次。在第一次迭代之后,它不再进入 jobTrigger(ch,jobConfig)
方法。 (或许不太清楚,因为豆子名称,如果我是对的)
My problem is that the creation of the Beans inside the iteration (Point 1) is just done one time. After the first iteration its not going inside the jobTrigger(ch, jobConfig)
method anymore. (More or less clear because of the bean name if I am right)
我在想什么,因为我使用 Quartz工厂
of Spring jobDetailFactoryBean.setBeanName()
方法用于创建更多具有不同名称的bean。
What I was thinking, because I use the Quartz factories
of Spring the jobDetailFactoryBean.setBeanName()
method is used to create more beans with different names.
不确定如何解决这个问题。代码正在运行,第一个创建的作业正在执行。但我需要更多工作。
Not sure how I can solve this problem. The Code is working and the first created job is executing right. But I need more jobs.
如何动态创建不同的工作?
修改:
我的完整配置类:
@Configuration
@ConfigurationProperties(prefix = "channelPartnerConfiguration", locations = "classpath:customer/channelPartnerConfiguration.yml")
public class ChannelPartnerProperties {
@Autowired
private List<ChannelPartner> channelPartners;
public List<ChannelPartner> getChannelPartners() {
return channelPartners;
}
public void setChannelPartners(List<ChannelPartner> channelPartners) {
this.channelPartners = channelPartners;
}
}
@Configuration
public class ChannelPartner {
private String code;
private String contracts;
private Boolean includeSpecialContracts;
private String touroperatorCode = "EUTO";
@Autowired
private PublishConfig publishConfig;
@Autowired
private BackupConfig backupConfig;
@Autowired
private List<JobConfig> jobConfigs;
//getter/setter
@Configuration
public class JobConfig {
private String schedule;
private boolean hotelEDF;
private boolean allotmentEDF;
private boolean enabled;
private String name;
//getter/setter
已添加投射到github 以更好地理解问题
推荐答案
您的列表将包含空值的原因是因为您正在调用的getObject方法应返回CronTrigger,该CronTrigger仅在spring启动弹簧上下文时由spring调用的afterPropertiesSet方法中启动。您可以在CronTriggerFactoryBean上手动调用此方法,这将允许您将其作为私有方法。
The reason why your list will contain null values is because the getObject method you are calling, should return the CronTrigger which is only initiated in afterPropertiesSet method called by spring when done initiating the spring context. You can call this method yourself manually on your CronTriggerFactoryBean, this will allow you to have it as a private method.
// Just to clarify, no annotations here
private CronTriggerFactoryBean jobTrigger(ChannelPartner ch, JobConfig jobConfig) throws ParseException {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(jobBean(ch, jobConfig).getObject());
cronTriggerFactoryBean.setCronExpression(jobConfig.getSchedule());
cronTriggerFactoryBean.setGroup("mainGroup");
cronTriggerFactoryBean.setBeanName(jobConfig.getName() + "Trigger");
cronTriggerFactoryBean.afterPropertiesSet();
return cronTriggerFactoryBean;
}
我确信还有很多其他方法可以做到这一点,如你提到过你自己做了一个解决方法,如果这不是你想要的或者需要我可以检查更多,如果我能找到更好的方法。
I'm sure there are many other ways of doing this as well, as you mentioned yourself you did a work-around for it, if this however is not what you want or need I can check some more if I can find a better way.
这篇关于如何以动态方式创建Spring Beans。使用Quartz SchedulerFactoryBean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!