Spring Boot中Quartz关联已有DataSource报JNDI错误求助
问题分析与解决方案
首先,咱们来拆解你遇到的问题:你想用Spring中已经配置好的MoliDBConfig数据源给Quartz用,但当前通过JNDI方式配置时抛出了NoInitialContextException,这是因为Spring Boot默认并没有启用JNDI上下文环境,Quartz找不到JNDI的初始化上下文,自然没法通过java:comp/env/jdbc/MoliDBConfig定位到数据源。
另外,你当前的Quartz配置类是手动初始化StdSchedulerFactory,这种方式没有和Spring的Bean管理体系整合起来,没法直接复用Spring已经创建好的DataSource Bean。
下面是具体的修正方案:
1. 调整quartz.properties配置
去掉或注释掉JNDI相关的数据源配置,因为咱们要直接复用Spring管理的DataSource,不需要让Quartz自己通过JNDI查找了。修改后的配置可以简化成这样:
# Configure Main Scheduler Properties org.quartz.scheduler.instanceName = MyClusteredScheduler org.quartz.scheduler.instanceId = AUTO # thread-pool org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount=2 org.quartz.threadPool.threadPriority = 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true # job-store org.quartz.jobStore.class = org.springframework.scheduling.quartz.LocalDataSourceJobStore org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate org.quartz.jobStore.useProperties = false org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.isClustered = true org.quartz.jobStore.clusterCheckinInterval = 20000 # 注释掉原来的数据源配置(包括JNDI和手动连接的部分) # Configure Datasources # org.quartz.dataSource.managedTXDS.jndiURL=java:comp/env/jdbc/MoliDBConfig # org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver # ... 其他手动数据源配置 # ClassLoader配置保留 org.quartz.scheduler.classLoadHelper.class=org.quartz.simpl.ThreadContextClassLoadHelper
2. 重构Quartz配置类,使用Spring的SchedulerFactoryBean
不要手动创建StdSchedulerFactory,改用Spring提供的SchedulerFactoryBean,它能自动整合Spring的Bean体系,直接注入咱们的DataSource。修改后的配置类代码如下:
@Configuration @Profile({"oracle-cloud","mysql-cloud"}) public class QrtzScheduler { private static final Logger LOGGER = LogManager.getLogger(QrtzScheduler.class); @Autowired private ApplicationContext applicationContext; // 注入Spring中已经配置好的DataSource @Autowired @Qualifier("MoliDBConfig") private DataSource dataSource; @PostConstruct public void init() { LOGGER.info("Hello world from Quartz..."); } @Bean public SpringBeanJobFactory springBeanJobFactory() { AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory(); LOGGER.debug("Configuring Job factory"); jobFactory.setApplicationContext(applicationContext); return jobFactory; } // 用SchedulerFactoryBean替代手动创建StdSchedulerFactory @Bean public SchedulerFactoryBean schedulerFactoryBean(Trigger trigger, JobDetail job) throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); // 加载quartz配置文件 factory.setConfigLocation(new ClassPathResource("quartz/quartz.properties")); // 设置Spring管理的DataSource factory.setDataSource(dataSource); // 设置自定义的JobFactory,支持Spring依赖注入 factory.setJobFactory(springBeanJobFactory()); // 设置要调度的Job和Trigger factory.setJobDetails(job); factory.setTriggers(trigger); // 启动时自动启动Scheduler factory.setAutoStartup(true); return factory; } // 这里的Scheduler Bean直接从SchedulerFactoryBean获取 @Bean public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); // 检查Job是否存在,存在则删除(保留你的原有逻辑) if (scheduler.checkExists(jobDetail().getKey())){ scheduler.deleteJob(jobDetail().getKey()); } LOGGER.debug("Starting Scheduler threads"); return scheduler; } @Bean public JobDetail jobDetail() { return JobBuilder.newJob() .ofType(ScheduledJob.class) .storeDurably() .withIdentity(JobKey.jobKey("Qrtz_Job_Detail")) .withDescription("Invoke Sample Job service...") .build(); } @Bean public Trigger trigger(JobDetail job) { int frequencyInMin = 5; LOGGER.info("Configuring trigger to fire every {} minutes", frequencyInMin); return TriggerBuilder.newTrigger().forJob(job) .withIdentity(TriggerKey.triggerKey("Qrtz_Trigger")) .withDescription("Sample trigger") .withSchedule(simpleSchedule().withIntervalInMinutes(frequencyInMin).repeatForever()) .build(); } }
为什么这样修改能解决问题?
SchedulerFactoryBean是Spring提供的Quartz整合类,它会自动处理Spring和Quartz之间的Bean生命周期管理,能直接使用Spring容器中的DataSource,不需要走JNDI。- 咱们直接注入了
@Qualifier("MoliDBConfig")的DataSource,确保Quartz复用的就是你原来配置好的那个数据源Bean。 - 去掉了Quartz配置文件中的JNDI数据源配置,避免Quartz尝试去查找不存在的JNDI上下文。
这样调整后,Quartz就能正常复用你Spring中配置的数据源,不会再出现JNDI相关的错误了。
内容的提问来源于stack exchange,提问作者James Hutchinson
相关产品推荐
相关产品推荐

