当我启动应用程序时,出于某种原因(对我来说不明显),它正在等待,直到实例化SchedulerFactoryBean
来实例化jtaTransactionManager
bean。当这样做时,Spring会从产生StackOverflow异常开始进入无限递归。
跟踪代码后,我发现没有循环依赖关系-事务管理器完全不依赖SchedulerAccessor
在底部的堆栈视图图像中,Proxy $ 98类是org.springframework.scheduling.quartz.SchedulerAccessor
的增强功能
编辑1:更新
正在发生的是SchedulerFactoryBean
正在bean工厂的preInstantiateSingletons()
方法中初始化。事务管理器不是单例,因此未预先初始化。当Spring接受建议时,它会尝试初始化Bean,但是建议会将其引导回相同的路径。
编辑2:内部(或地狱)
弹簧类org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration
将transactionManager属性实现为LazyProxy。
这在初始化代码构造实际的TransactionManager bean之前执行得很好。在某个时候,该类需要在TransactionManager上下文中调用事务,这将导致spring容器尝试实例化bean。由于有关于bean代理的建议,因此SimpleBatchConfiguration
类中的方法拦截器将尝试执行getTransaction()
方法,这又将导致spring容器尝试实例化bean,该bean调用了intergceptor ,它尝试执行getTransaction()
方法...。
编辑3:@EnableBatchProcessing
我在这里经常使用“明显”一词,因为它是基于启动过程中失败模式的猜测。
(显然)无法配置@EnableBatchProcessing
注释中使用的事务管理器。剥离@EnableBatchProcessing
消除了递归调用,但使我明显具有循环依赖性。
由于某种未知的原因,即使我已经跟踪并且该代码只被调用了一次,但它失败了,因为它认为名为“ configurer”的bean已经在创建中:
@Bean({ "configurer", "defaultBatchConfigurer" })
@Order(1)
public BatchConfigurer configurer() throws IOException, SystemException {
DefaultBatchConfigurer result = new DefaultBatchConfigurer(securityDataSource(), transactionManager());
return result;
}
启动递归的代码是:
protected void registerJobsAndTriggers() throws SchedulerException {
TransactionStatus transactionStatus = null;
if (this.transactionManager != null) {
transactionStatus = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
}
AppInitializer启动代码:
@Override
public void onStartup(ServletContext container) throws ServletException {
Logger logger = LoggerFactory.getLogger(this.getClass());
try {
// DB2XADataSource db2DataSource = null;
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(DatabaseConfig.class);
rootContext.register(SecurityConfig.class);
rootContext.register(ExecutionContextConfig.class);
rootContext.register(SimpleBatchConfiguration.class);
rootContext.register(MailConfig.class);
rootContext.register(JmsConfig.class);
rootContext.register(SchedulerConfig.class);
rootContext.refresh();
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
jtaTransactionManager
中DatabaseConfig
bean的构造
@Bean(destroyMethod = "shutdown")
@Order(1)
public BitronixTransactionManager bitronixTransactionManager() throws IOException, SystemException {
btmConfig();
BitronixTransactionManager bitronixTransactionManager = TransactionManagerServices.getTransactionManager();
bitronixTransactionManager.setTransactionTimeout(3600); // TODO: Make this configurable
return bitronixTransactionManager;
}
@Bean({ "transactionManager", "jtaTransactionManager" })
@Order(1)
public PlatformTransactionManager transactionManager() throws IOException, SystemException {
JtaTransactionManager mgr = new JtaTransactionManager();
mgr.setTransactionManager(bitronixTransactionManager());
mgr.setUserTransaction(bitronixTransactionManager());
mgr.setAllowCustomIsolationLevels(true);
mgr.setDefaultTimeout(3600);
mgr.afterPropertiesSet();
return mgr;
}
SchedulerFactoryBean
中SchedulerConfig
的构造
@Autowired
@Qualifier("transactionManager")
public void setJtaTransactionManager(PlatformTransactionManager jtaTransactionManager) {
this.jtaTransactionManager = jtaTransactionManager;
}
@Bean
@Order(3)
public SchedulerFactoryBean schedulerFactoryBean() {
Properties quartzProperties = new Properties();
quartzProperties.put("org.quartz.jobStore.driverDelegateClass",
delegateClass.get(getDatabaseType()));
quartzProperties.put("org.quartz.jobStore.tablePrefix", getTableSchema()
+ ".QRTZ_");
quartzProperties.put("org.quartz.jobStore.class",
org.quartz.impl.jdbcjobstore.JobStoreCMT.class.getName());
quartzProperties.put("org.quartz.scheduler.instanceName",
"MxArchiveScheduler");
quartzProperties.put("org.quartz.threadPool.threadCount", "3");
SchedulerFactoryBean result = new SchedulerFactoryBean();
result.setDataSource(securityDataSource());
result.setNonTransactionalDataSource(nonJTAsecurityDataSource());
result.setTransactionManager(jtaTransactionManager);
result.setQuartzProperties(quartzProperties);
return result;
}
答案 0 :(得分:0)
要想找出解决办法的步骤,有许多不可能的事情。我最终弄乱了它,直到它起作用为止,因为异常消息不是信息。
最后,结果如下:
重构了包装,因此作业/步骤范围的和全局范围的bean位于不同的包中,因此上下文扫描可以轻松地在正确的上下文中捕获正确的bean。
克隆并修改org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration
以获取我想要用于我的应用程序的bean
取出@EnableBatchProcessing
批注。由于我已经不太会自动地进行初始化了,所以一切都进行了两次初始化,这造成了混乱
清理了XA和非XA数据源的用法
使用@Primary
注释选择正确的内容(在这里咬舌头-无法隐式告诉框架在出现问题时始终使用“此一个”来告诉框架要使用几个数据源中的哪个) “?真的吗?)