龙岩新罗区建设局网站,分销商城开发,新乡市置顶网络技术有限公司,网络私人定制网站目录 前言任务注册注册方法 前言
看该文章之前#xff0c;最好看一下之前的文章#xff0c;比较方便我们理解 XXL-Job详解#xff08;一#xff09;#xff1a;组件架构 XXL-Job详解#xff08;二#xff09;#xff1a;安装部署 XXL-Job详解#xff08;三#xff0… 目录 前言任务注册注册方法 前言
看该文章之前最好看一下之前的文章比较方便我们理解 XXL-Job详解一组件架构 XXL-Job详解二安装部署 XXL-Job详解三任务开发
任务注册
我们在执行器开发任务的时候只需要一个XxlJob注解就可以定义一个任务那么它是怎么做到的呢
xxl-job之前的版本中是通过继承 IJobHandler 和在类上加注解的方式进行任务标识在最新版中则抛弃了原有的做法将任务的粒度细化到了方法级别。
前者的好处是任务编写的范式已经规定好只需要重写对应抽象类中的方法并加上注解但每一次编写新的任务执行程序都需要创建新的类来重新实现接口。后者的好处是在于细化了任务的粒度将注解细化到了方法级别不需要再重复地继承方法很好地实现了类的复用。
在SpringBoot版本中我们使用的执行器是XxlJobSpringExecutor它是XxlJobExecutor的子类并且实现了ApplicationContextAware 、SmartInitializingSingleton、DisposableBean 三个接口
public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {
}下面介绍一下XxlJobSpringExecutor实现的三个接口
ApplicationContextAware ApplicationContextAware 是 Spring 框架中的一个接口用于在 Spring 容器中获取 ApplicationContext 对象。通过实现这个接口可以将 Spring 容器中的上下文信息注入到 JavaBean 中从而让 JavaBean 访问 Spring 配置文件中的 Bean 和其他资源。
当一个类实现 ApplicationContextAware 接口时Spring 容器会自动将当前应用程序的 ApplicationContext 对象注入到该类的 setApplicationContext 方法中。这样该类就可以通过 ApplicationContext 对象访问 Spring 容器中的其他 Bean 和资源。
SmartInitializingSingleton SmartInitializingSingleton 是 Spring 框架中的一个接口它用于定义在单例对象初始化时执行特定操作的接口。主要用于在Spring容器启动完成时进行扩展操作即afterSingletonsInstantiated()方法
DisposableBean DisposableBean是在Spring容器关闭的时候预留的一个扩展点实现DisposableBean接口并重写destroy()可以在Spring容器销毁bean的时候获得一次回调
注册方法
下面是XxlJobSpringExecutor实现SmartInitializingSingleton接口的afterSingletonsInstantiated方法任务注册就在这个方法里 Overridepublic void afterSingletonsInstantiated() {// init JobHandler Repository/*initJobHandlerRepository(applicationContext);*/// init JobHandler Repository (for method)initJobHandlerMethodRepository(applicationContext);// refresh GlueFactoryGlueFactory.refreshInstance(1);// super starttry {super.start();} catch (Exception e) {throw new RuntimeException(e);}}可以看到在 afterSingletonsInstantiated 方法做了这样几件事情
1、初始化任务执行程序仓库即进行任务注册 2、刷新GlueFactory获取SpringGlueFactory用于动态脚本任务 3、启动执行器此处调用父类start()方法
可以看到任务注册的方法就在initJobHandlerMethodRepository方法
private void initJobHandlerMethodRepository(ApplicationContext applicationContext) {if (applicationContext null) {return;}// 获取bean名称列表String[] beanDefinitionNames applicationContext.getBeanNamesForType(Object.class, false, true);for (String beanDefinitionName : beanDefinitionNames) {// 从上下文中根据bean元数据名称获取bean对象Object bean applicationContext.getBean(beanDefinitionName);MapMethod, XxlJob annotatedMethods null; // referred to org.springframework.context.event.EventListenerMethodProcessor.processBeantry {
// 根据bean类元信息获取被XxlJob注解的方法annotatedMethods MethodIntrospector.selectMethods(bean.getClass(),new MethodIntrospector.MetadataLookupXxlJob() {Overridepublic XxlJob inspect(Method method) {return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);}});} catch (Throwable ex) {logger.error(xxl-job method-jobhandler resolve error for bean[ beanDefinitionName ]., ex);}//如果没有xxljob方法则跳过if (annotatedMethodsnull || annotatedMethods.isEmpty()) {continue;}for (Map.EntryMethod, XxlJob methodXxlJobEntry : annotatedMethods.entrySet()) {//获取被注解的方法Method executeMethod methodXxlJobEntry.getKey();//获取注解信息XxlJob xxlJob methodXxlJobEntry.getValue();// 注册handlerregistJobHandler(xxlJob, bean, executeMethod);}}}protected void registJobHandler(XxlJob xxlJob, Object bean, Method executeMethod){if (xxlJob null) {return;}//获取任务名称String name xxlJob.value();//make and simplify the variables since theyll be called several times laterClass? clazz bean.getClass();String methodName executeMethod.getName();//判断任务名称是否有效if (name.trim().length() 0) {throw new RuntimeException(xxl-job method-jobhandler name invalid, for[ clazz # methodName ] .);}//检查当前任务名是否已经被使用注意这里是通过任务名称来进行任务判重的if (loadJobHandler(name) ! null) {throw new RuntimeException(xxl-job jobhandler[ name ] naming conflicts.);}executeMethod.setAccessible(true);// 设置初始化方法和销毁方法Method initMethod null;Method destroyMethod null;if (xxlJob.init().trim().length() 0) {try {initMethod clazz.getDeclaredMethod(xxlJob.init());initMethod.setAccessible(true);} catch (NoSuchMethodException e) {throw new RuntimeException(xxl-job method-jobhandler initMethod invalid, for[ clazz # methodName ] .);}}if (xxlJob.destroy().trim().length() 0) {try {destroyMethod clazz.getDeclaredMethod(xxlJob.destroy());destroyMethod.setAccessible(true);} catch (NoSuchMethodException e) {throw new RuntimeException(xxl-job method-jobhandler destroyMethod invalid, for[ clazz # methodName ] .);}}//进行任务处理程序注册registJobHandler(name, new MethodJobHandler(bean, executeMethod, initMethod, destroyMethod));}首先initJobHandlerMethodRepository方法的applicationContext参数就是通过ApplicationContextAware 获取的下面我们来看下initJobHandlerMethodRepository方法的具体逻辑
1、从ApplicationContext中获取所有Bean元数据名称通过Bean元数据名称获取所有Bean 2、遍历获取到的Bean找到有XxlJob注解的类获取类中被注解的所有方法 3、获取被注解方法的相应信息根据注解中的任务名称调用loadJobHandler(name)方法检查该任务是否已经注册 4、进行方法编写范式检查主要检查方法名称、入参类型以及返回值类型是否符合要求 5、设置被注解方法的初始化方法和销毁方法 6、最后将上述被注解方法注册到任务处理程序仓库中