Quartz调度器:List\String\转GroupMatcher\JobKey\
2025-03-22 10:42:30
如何将 List<String> 转换为 GroupMatcher<JobKey>?
遇到一个Quartz 调度器相关的小麻烦:需要遍历所有Job Group,但scheduler.getJobGroupNames()
返回的是List<String>
,而我想用GroupMatcher<JobKey>
进行处理。直接遍历会报错:类型不匹配。 这篇文章就来聊聊如何解决这个问题,以及背后的一些小知识。
问题根源:类型不兼容
问题出在 Quartz 的 API 设计上。 scheduler.getJobGroupNames()
返回的是 Job Group 名称的字符串列表,而我们想用的GroupMatcher
是一个泛型类,用于匹配 JobKey
对象。字符串和 GroupMatcher<JobKey>
根本不是一回事,直接拿来循环当然不行。
解决方案:多种姿势
解决类型不匹配的问题,思路无非是进行转换,下面列出几种把List<String>
变成可以和GroupMatcher<JobKey>
打交道的办法:
方案一: 构造GroupMatcher,再筛选
核心思路:用 GroupMatcher 的静态方法创建匹配特定 Group 的Matcher, 再去和所有 jobKey 比对.
-
原理:
GroupMatcher.groupEquals(groupName)
:创建只匹配指定 Group Name 的 Matcher。scheduler.getJobKeys(groupMatcher)
:获取匹配指定 GroupMatcher 的所有 JobKey。
-
代码示例:
List<String> jobGroupNames = scheduler.getJobGroupNames(); for (String groupName : jobGroupNames) { GroupMatcher<JobKey> groupMatcher = GroupMatcher.groupEquals(groupName); Set<JobKey> jobKeys = scheduler.getJobKeys(groupMatcher); // 现在可以对 jobKeys 进行操作了 for (JobKey jobKey : jobKeys) { // 处理每个 JobKey System.out.println("Job Key: " + jobKey); } }
-
安全提示:
如果获取jobKeys
目的是进行删除或者暂停操作, 要小心 Quartz 内部 job 的 group。 误删可能会导致调度器出问题。
方案二: 使用groupContains
与方法类似,只是使用了不同的GroupMatcher
。
-
原理:
GroupMatcher.groupContains(groupName)
创建一个 Matcher,匹配Group名称包含给定字符串的任何 JobKey。 这比精确匹配更宽松。 -
代码示例:
List<String> jobGroupNames = scheduler.getJobGroupNames(); for (String groupName : jobGroupNames) { GroupMatcher<JobKey> groupMatcher = GroupMatcher.groupContains(groupName); Set<JobKey> jobKeys = scheduler.getJobKeys(groupMatcher); for (JobKey jobKey : jobKeys) { System.out.println("Job Key: " + jobKey); } }
-
注意:
如果你确定 Job Group 名称不会有重叠部分,那么
groupContains
和groupEquals
效果一样。 但如果 Group 名称有包含关系(例如 "GroupA" 和 "GroupA_Sub"),groupContains("GroupA")
会把两个 Group 的 Job 都匹配出来。
方案三:直接构造Set<JobKey>
前面的方法都是把 List 拆开成单个 groupName,再去查询. 我们也可以利用现有 list,直接创建一个包含关系的 matcher.
-
原理
先利用
GroupMatcher.groupEquals(groupName)
,创建一个匹配指定group的matcher。
用获取的Set<Jobkey>
传入scheduler.getJobKeys()
。 -
代码演示
import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.impl.matchers.GroupMatcher; import java.util.HashSet; import java.util.List; import java.util.Set; public class JobGroupConverter { public void processJobGroups(Scheduler scheduler) throws SchedulerException{ List<String> jobGroupNames = scheduler.getJobGroupNames(); Set<GroupMatcher<JobKey>> matchers = new HashSet<>(); for(String groupName: jobGroupNames) { matchers.add(GroupMatcher.groupEquals(groupName)); } for(GroupMatcher<JobKey> matcher: matchers){ Set<JobKey> jobKeys = scheduler.getJobKeys(matcher); for (JobKey jobKey : jobKeys) { //处理jobKey System.out.println("Group: " + matcher.getCompareToValue() + ", Job Key: "+ jobKey); } } } }
这样就可以直接获得
Set<GroupMatcher<JobKey>>
了,然后对它进行循环遍历等. -
扩展技巧
如果不仅仅要根据 GroupName 过滤,还要加上其他条件,可以将`GroupMatcher`和其他`Matcher`组合使用:
AndMatcher.and(groupMatcher, anotherMatcher)
方案四:暴力转换(不推荐)
如果实在要得到 Set<GroupMatcher<JobKey>>
, 还一种“简单粗暴”的办法,但不推荐这样做,只是为了展示一个思路:
-
原理:
直接遍历
jobGroupNames
,每一个 GroupName 都创建一个GroupMatcher<JobKey>
,然后加入Set.
这本质上是创建了多个只匹配单个Group的Matcher, 然后放入了一个 Set. -
代码示例:
import org.quartz.JobKey; import org.quartz.impl.matchers.GroupMatcher; import java.util.HashSet; import java.util.List; import java.util.Set; public Set<GroupMatcher<JobKey>> convert(List<String> jobGroupNames) { Set<GroupMatcher<JobKey>> groupMatchers = new HashSet<>(); for (String groupName : jobGroupNames) { groupMatchers.add(GroupMatcher.groupEquals(groupName)); } return groupMatchers; } //获取到 Set<GroupMatcher<JobKey>> groupMatchers 后可以进行迭代操作。
-
为什么不推荐?
这种做法实际上就是把一个简单问题复杂化了。 我们根本不需要这样 “转换” 出
Set<GroupMatcher<JobKey>>
。方案一,方案二或者三,都能直接处理原始的List<String>
,更简洁,更符合 Quartz 的设计思想。
总结
小问题背后,是对 Quartz 匹配机制的理解。记住,GroupMatcher
是用来匹配 JobKey
的,而 scheduler.getJobGroupNames()
给的是字符串。 理解了这个,根据需求选择合适的方法就好。大多数情况下,使用GroupMatcher.groupEquals
或者GroupMatcher.groupContains
来处理已经足够了。