Spring Batch+Quartz可执行Jar启动报错:无法找到NamespaceHandler
你遇到的BeanDefinitionParsingException核心原因是可执行Jar打包时,多个Spring依赖中的META-INF/spring.handlers和META-INF/spring.schemas文件被互相覆盖。本地运行时类加载器能从各个依赖Jar中读取这些文件,但打包成单个Jar时,默认Gradle的jar任务只会保留最后一个被处理的依赖中的这些文件,导致context命名空间对应的处理器丢失。另外你的配置文件里还有一个笔误需要优先修正。
1. 先修正applicationContext.xml中的致命笔误
你的jobRepository bean里,transactionManager的引用写错了:
<property name="transactionManager" ref="traJnsactionManager" />
应该改成:
<property name="transactionManager" ref="transactionManager" />
这个笔误会导致后续启动时找不到对应的事务管理器bean,必须先修复。
2. 修改Gradle打包配置,合并Spring命名空间文件
在build.gradle的jar任务中添加配置,确保META-INF/spring.handlers和META-INF/spring.schemas被合并而非覆盖。修改后的完整jar任务如下:
jar { manifest { attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version, 'Main-Class': 'org.yourpackage.MyJobScheduler' // 注意修正这里的包名,原配置的org..是笔误 } baseName = 'batchjob' // 合并Spring命名空间配置文件,避免被覆盖 into('META-INF') { from configurations.compile.collect { if (it.name.endsWith('.jar')) { zipTree(it).matching { include 'spring.handlers', 'spring.schemas' } } } // 对目标文件执行追加合并,而非替换 eachFile { file -> if (file.name in ['spring.handlers', 'spring.schemas']) { file.path = file.name // 确保文件路径为META-INF/xxx,而非嵌套路径 file.filter { line -> !line.trim().isEmpty() } // 清理空行 file.mergeStrategy = MergeStrategy.FILE_APPEND // 追加内容 } } } from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } }
这里的关键是使用MergeStrategy.FILE_APPEND,让所有Spring依赖中的命名空间处理器配置都被保留下来。
3. 修正主类的包名配置
你manifest中的Main-Class写了org..MyJobScheduler,连续的两个点是笔误,需要改成实际的全类名(比如org.batch.MyJobScheduler),否则JVM无法找到主类。
4. 优化Quartz调度器的Spring上下文集成
如果你的MyJobBuilder需要访问Spring容器中的bean(比如versionComparisonTasklet),建议从Spring上下文获取Scheduler实例,而非直接使用StdSchedulerFactory.getDefaultScheduler(),修改主类代码如下:
public static void main(String[] args) throws SchedulerException { // 加载Spring应用上下文 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); JobDetail j = JobBuilder.newJob(MyJobBuilder.class).build(); Trigger t = TriggerBuilder.newTrigger() .withIdentity("CroneTrigger") .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(72).repeatForever()) .build(); // 从Spring上下文获取Scheduler,保证Job能访问容器内的bean Scheduler s = context.getBean(Scheduler.class); s.start(); s.scheduleJob(j, t); }
最后步骤
执行gradle clean jar重新生成可执行Jar,然后用java -jar batchjob-1.0.jar运行,即可解决命名空间处理器缺失的问题。
内容的提问来源于stack exchange,提问作者arvin_codeHunk

