Springカスタム注釈によるタスクルーティング

3909 ワード

Spring mvcの開発では、どのURLの要求を処理するかをRequestMappingで組み合わせることができる.同様に、異なるタスクタイプに従って異なるタスクアクチュエータにルーティングできるタスクスケジューラが必要です.その本質は,外部パラメータによる一次ルーティングがSpring mvcと類似していることである.Spring mvcの実装原理を簡単に見た後,カスタム注釈を用いて以上の機能を実現することにした.
カスタムTaskHandler注記
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface TaskHandler {

    String taskType() default "";
}

@Componentは、springの起動中にコンテナにスキャンされ、注入されることを示すタスクプロセッサの注記を定義しました.taskTypeはタイプを表します.
タスクプロセッサ定義
public abstract class AbstractTaskHandler {

    /**
     *      
     *
     * @param task   
     * @return     
     */
     public abstract BaseResult execute(Task task);
}

以上では、タスク実行のプロセッサを定義し、他のすべての特定のタスク実行器がこの方法を継承して実装します.ここでTaskは、タスクId、タスクの実行に必要なパラメータなど、タスクの定義を表す.
タスクプロセッサ実装
次に、特定のタスクプロセッサを実装できます.
@TaskHandler(taskType = "UserNameChanged")
public class UserNameChangedSender extends AbstractTaskHandler {
    @Override
    public BaseResult execute(Task task) {
      return new BaseResult();
    }
}

以上、ユーザー名変更通知のタスクプロセッサを実装しましたが、具体的なビジネスロジックはここでは実装されていません.
そのうち:@TaskHandler(taskType="UserName Changed")では、ユーザー名の変更を処理するタスクを指定します.
タスク処理Handler登録
public class TaskHandlerRegister extends ApplicationObjectSupport {

    private final static Map TASK_HANDLERS_MAP = new HashMap<>();

    private static final Logger LOGGER = LoggerFactory.getLogger(TaskHandlerRegister.class);

    @Override
    protected void initApplicationContext(ApplicationContext context) throws BeansException {
        super.initApplicationContext(context);
        Map taskBeanMap = context.getBeansWithAnnotation(TaskHandler.class);
        taskBeanMap.keySet().forEach(beanName -> {
            Object bean = taskBeanMap.get(beanName);
            Class clazz = bean.getClass();
            if (bean instanceof AbstractTaskHandler && clazz.getAnnotation(TaskHandler.class) != null) {
                TaskHandler taskHandler = (TaskHandler) clazz.getAnnotation(TaskHandler.class);
                String taskType = taskHandler.taskType();
                if (TASK_HANDLERS_MAP.keySet().contains(taskType)) {
                    throw new RuntimeException("TaskType has Exits. TaskType=" + taskType);
                }
                TASK_HANDLERS_MAP.put(taskHandler.taskType(), (AbstractTaskHandler) taskBeanMap.get(beanName));
                LOGGER.info("Task Handler Register. taskType={},beanName={}", taskHandler.taskType(), beanName);
            }
        });
    }

    public static AbstractTaskHandler getTaskHandler(String taskType) {
        return TASK_HANDLERS_MAP.get(taskType);
    }
}

ここでSpringのApplicationObjectSupportクラスを継承し、具体的な登録手順は以下の通りです.
  • Spring完了beanの初期化
  • springのコンテナを検索します.TaskHandler注記付きbean
  • beanがAbstractTaskHandlerタイプであるかどうかを検証し、taskType
  • を取得する
  • このbeanをTASK_に置くHANDLERS_MAPコンテナ、すなわち登録完了
  • タスク実行
    次にタスクの実行を見てみましょう
    public class TaskExecutor implements Job {
    
        private static final String TASK_TYPE = "taskType";
    
        @Override
        public BaseResult execute(Task task){
            String taskType=task.getTaskType();
            if (TaskHandlerRegister.getTaskHandler(taskType) == null) {
                throw new RuntimeException("can't find taskHandler,taskType=" + taskType);
            }
            AbstractTaskHandler abstractHandler = TaskHandlerRegister.getTaskHandler(taskType);
            return abstractHandler.execute(task);
        }
    }

    ここでタスクを開始したのはJobで、具体的なプロセスは以下の通りです.
  • このタスクタイプを検証し、登録センターに関連Handler
  • が登録されているかどうかを確認します.
  • タスク登録センタから対応する処理を取得するHandelr
  • .
  • このHandelr
  • を実行する
    以上のプロセスが完了し,注釈に基づくタスクルーティングプロセスを実現できる.現在の構想はSpring mvcのRequestMappingの設計構想から来ている.