Quartz SchedulerFactoryBean异常--Spring自动装配惹的祸

本文详细解析了Spring配置文件中启用了自动装配模式导致QuartzSchedulerFactoryBean初始化失败的问题,分析了错误产生的原因,并提供了屏蔽自动装配和启用RAMJobStore模式的解决方案。

Quartz SchedulerFactoryBean异常--Spring自动装配惹的祸  


2011-02-12 20:45:02|  分类: Spring |  标签:quartz  datasource  bean  spring  property   |字号 订阅
Spring的配置文件,启用了自动装配模式:
<beans default-autowire="byName">


<bean id="dataSource" class="..."></bean>


<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
  <property name="triggers">
   <list><ref bean="clearLogsTrigger" /></list>
  </property>
 </bean>


  ...


</beans>


则此时会产生如下错误:


Error creating bean with name 'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' defined in file [E:\workspace\eis_oracle2\web\WEB-INF\classes\conf\spring\eisSystemScheduleContext.xml]: Invocation of init method failed; nested exception is org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: ORA-00942: table or view does not exist


原因:其实这都是Spring的自动装配惹得祸,当存在dataSource的bean,在初始化SchedulerFactoryBean时就自动装配该dataSource属性,此时就启用了jobstore的LocalDataSourceJobStore模式使用数据库来维持状态,quartz的jobstore会从数据库中查询任务。quartz使用数据库进行job状态的维护,但是在数据库中没有找到相应的table,从而无法正常初始化scheduler 。






解决:屏蔽掉自动装配,如下:


<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="false">
  <property name="triggers">
   <list><ref bean="clearLogsTrigger" /></list>
  </property>
 </bean>


另:启用jobstore的RAMJobStore(内存存储的)模式,配置如下:


<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="false">
  <property name="triggers">
   <list> <ref bean="clearLogsTrigger" /></list>
  </property>
  <property name="quartzProperties">
   <props>
    <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
   </props>
  </property>
 </bean>


当设置了dataSource属性,jobStore属性设置将无效,原因是:


if (this.dataSource != null) {     
    mergedProps.put(StdSchedulerFactory.PROP_JOB_STORE_CLASS, LocalDataSourceJobStore.class.getName());   
}  


详细介绍请参见 SchedulerFactoryBean 方法 setDataSource(DataSource)的javadoc: 
Set the default DataSource to be used by the Scheduler. If set, this will override corresponding settings in Quartz properties. 


Note: If this is set, the Quartz settings should not define a job store "dataSource" to avoid meaningless double configuration. 


A Spring-specific subclass of Quartz' JobStoreCMT will be used. It is therefore strongly recommended to perform all operations on the Scheduler within Spring-managed (or plain JTA) transactions. Else, database locking will not properly work and might even break (e.g. if trying to obtain a lock on Oracle without a transaction). 


Supports both transactional and non-transactional DataSource access. With a non-XA DataSource and local Spring transactions, a single DataSource argument is sufficient. In case of an XA DataSource and global JTA transactions, SchedulerFactoryBean's "nonTransactionalDataSource" property should be set, passing in a non-XA DataSource that will not participate in global transactions.

 

补单系统源码

### 改造 `spring-boot-starter-quartz` 源码 为了实现对 `spring-boot-starter-quartz` 的改造,可以遵循以下方法来满足特定的自定义需求: #### 1. 获取并理解现有代码结构 首先克隆 Spring Boot GitHub仓库中的相应版本分支,找到 `spring-boot-starters` 下的 `spring-boot-starter-quartz` 文件夹。这里包含了 Quartz Starter 所有必要的配置类和服务组件。 ```bash git clone https://github.com/spring-projects/spring-boot.git --branch v2.1.0.RELEASE cd spring-boot/spring-boot-project/spring-boot-starters/spring-boot-starter-quartz/ ``` 此操作允许深入研究当前启动器的工作机制及其依赖注入模式[^1]。 #### 2. 修改或扩展功能 针对具体业务逻辑的需求调整,可以通过继承原有类或者创建新的服务 bean 来完成。例如,如果希望更改默认的任务调度策略,则可以在项目中添加如下 Java 配置类: ```java @Configuration public class CustomQuartzConfig { @Autowired private DataSource dataSource; @Bean public JobFactory jobFactory() { AutowireCapableBeanFactory factory = applicationContext.getAutowiringSupport().getAutowireCapableBeanFactory(); return new AdaptableJobFactory(factory); } @Bean public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setOverwriteExistingJobs(true); factory.setAutoStartup(true); factory.setDataSource(dataSource); factory.setJobFactory(jobFactory); // 自定义属性设置 Properties prop = new Properties(); prop.put("org.quartz.scheduler.instanceName", "CustomScheduler"); prop.put("org.quartz.threadPool.threadCount", "3"); factory.setQuartzProperties(prop); return factory; } } ``` 这段代码展示了如何通过覆盖原有的 Bean 定义来自定义任务工厂以及调度器的行为特性[^2]。 #### 3. 解决潜在冲突问题 对于提到的同时引入 `spring-boot-starter-websocket` 和 `spring-boot-starter-quartz` 导致 NullBean 错误的情况,在上述例子的基础上进一步确保 TaskScheduler 实例化的唯一性和正确性非常重要。这可能涉及到检查是否有重复注册相同类型的 Beans 或者调整自动装配顺序等问题。 #### 4. 测试验证改动效果 最后一步是对所做的任何变更进行全面测试,包括单元测试和集成测试,以确认新行为符合预期,并且不会破坏其他部分的功能稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值