返回

Quartz调度器:List\String\转GroupMatcher\JobKey\

java

如何将 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 比对.

  1. 原理:

    • GroupMatcher.groupEquals(groupName):创建只匹配指定 Group Name 的 Matcher。
    • scheduler.getJobKeys(groupMatcher):获取匹配指定 GroupMatcher 的所有 JobKey。
  2. 代码示例:

    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);
        }
    }
    
  3. 安全提示:
    如果获取jobKeys目的是进行删除或者暂停操作, 要小心 Quartz 内部 job 的 group。 误删可能会导致调度器出问题。

方案二: 使用groupContains

与方法类似,只是使用了不同的GroupMatcher

  1. 原理:

    GroupMatcher.groupContains(groupName)创建一个 Matcher,匹配Group名称包含给定字符串的任何 JobKey。 这比精确匹配更宽松。

  2. 代码示例:

    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);
        }
    }
    
  3. 注意:

    如果你确定 Job Group 名称不会有重叠部分,那么groupContainsgroupEquals效果一样。 但如果 Group 名称有包含关系(例如 "GroupA" 和 "GroupA_Sub"),groupContains("GroupA") 会把两个 Group 的 Job 都匹配出来。

方案三:直接构造Set<JobKey>

前面的方法都是把 List 拆开成单个 groupName,再去查询. 我们也可以利用现有 list,直接创建一个包含关系的 matcher.

  1. 原理

    先利用GroupMatcher.groupEquals(groupName),创建一个匹配指定group的matcher。
    用获取的Set<Jobkey>传入scheduler.getJobKeys()

  2. 代码演示

    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>>了,然后对它进行循环遍历等.

  3. 扩展技巧

    如果不仅仅要根据 GroupName 过滤,还要加上其他条件,可以将`GroupMatcher`和其他`Matcher`组合使用:
    

    AndMatcher.and(groupMatcher, anotherMatcher)

方案四:暴力转换(不推荐)

如果实在要得到 Set<GroupMatcher<JobKey>>, 还一种“简单粗暴”的办法,但不推荐这样做,只是为了展示一个思路:

  1. 原理:

    直接遍历jobGroupNames,每一个 GroupName 都创建一个GroupMatcher<JobKey>,然后加入Set.
    这本质上是创建了多个只匹配单个Group的Matcher, 然后放入了一个 Set.

  2. 代码示例:

    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 后可以进行迭代操作。
    
    
  3. 为什么不推荐?

    这种做法实际上就是把一个简单问题复杂化了。 我们根本不需要这样 “转换” 出 Set<GroupMatcher<JobKey>>。方案一,方案二或者三,都能直接处理原始的 List<String>,更简洁,更符合 Quartz 的设计思想。

总结

小问题背后,是对 Quartz 匹配机制的理解。记住,GroupMatcher 是用来匹配 JobKey 的,而 scheduler.getJobGroupNames() 给的是字符串。 理解了这个,根据需求选择合适的方法就好。大多数情况下,使用GroupMatcher.groupEquals或者GroupMatcher.groupContains来处理已经足够了。