XXL-JOB注册和执行原理

392 阅读2分钟

一.注册原理

1.XxlJobSpringExecutor的结构
image.png 我们打开源码里的xxl-job-core项目的类XxlJobSpringExecutor,发现这个类:
1.扩展了类XxlJobExecutor的destroy方法,用于销毁bean image.png 2.实现了接口ApplicationContextAware的方法setApplicationContext来获取spring的应用上下文 image.png 3.实现了接口SmartInitializingSingleton的方法afterSingletonsInstantiated来初始化JobHandler Repository(这个是最核心的方法) image.png 在Spring 的bean的生命周期里,当所有单例 bean 都初始化完成以后, Spring的IOC(容器会回调该接口的 afterSingletonsInstantiated()方法 XXL-JOB就是在这里获取到spring的bean容器里的@XxjJob修饰的方法,并注册到JobHandler Repository 里的.

下面我们来debug一下

1.启动执行器项目(客户端)

2.在initJobHandlerMethodRepositorydage打个断点,条件为bean的名字(这里以注解@XxlJob所在的类SampleXxlJob为例)

image.png image.png

3.执行initJobHandlerMethodRepository具体逻辑

3.1获取对应的bean:sampleXxlJob

Object bean = applicationContext.getBean(beanDefinitionName);

image.png

3.2获取到注解@xxlJob的修饰的方法,并保存到Map annotatedMethods里面

Map<Method, XxlJob> annotatedMethods = null;   // referred to :org.springframework.context.event.EventListenerMethodProcessor.processBean
try {
    annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
            new MethodIntrospector.MetadataLookup<XxlJob>() {
                @Override
                public XxlJob inspect(Method method) {
                    return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
                }
            });
}

image.png 例子里@XxlJob修饰了方法demoJobHandler,shardingJobHandler,commandJobHandler,httpJobHandler,demoJobHandler2

3.3依次遍历annotatedMethods,并调用registJobHandler方法来 把JobHandler名称,bean名称,注解@xxlJob的修饰的方法(executeMethod)保存到jobHandlerRepository对象中

private void initJobHandlerMethodRepository(ApplicationContext applicationContext) {
    if (applicationContext == null) {
        return;
    }
    // init job handler from method
    String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
    for (String beanDefinitionName : beanDefinitionNames) {
       //1.获取对应的bean:sampleXxlJob
        Object bean = applicationContext.getBean(beanDefinitionName);

        //2.获取到注解@xxlJob的修饰的方法,并保存到Map annotatedMethods里面
        Map<Method, XxlJob> annotatedMethods = null;   // referred to :org.springframework.context.event.EventListenerMethodProcessor.processBean
        try {
            annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
                    new MethodIntrospector.MetadataLookup<XxlJob>() {
                        @Override
                        public 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);
        }
        if (annotatedMethods==null || annotatedMethods.isEmpty()) {
            continue;
        }

        //3.依次遍历annotatedMethods,并调用registJobHandler方法来 把JobHandler名称,bean名称,注解@xxlJob的修饰的方法(executeMethod)保存到jobHandlerRepository对象中
        for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
            Method executeMethod = methodXxlJobEntry.getKey();
            XxlJob xxlJob = methodXxlJobEntry.getValue();
            if (xxlJob == null) {
                continue;
            }

            String name = xxlJob.value();
            if (name.trim().length() == 0) {
                throw new RuntimeException("xxl-job method-jobhandler name invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
            }
            if (loadJobHandler(name) != null) {
                throw new RuntimeException("xxl-job jobhandler[" + name + "] naming conflicts.");
            }

            executeMethod.setAccessible(true);

            // init and destory
            Method initMethod = null;
            Method destroyMethod = null;

            if (xxlJob.init().trim().length() > 0) {
                try {
                    initMethod = bean.getClass().getDeclaredMethod(xxlJob.init());
                    initMethod.setAccessible(true);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("xxl-job method-jobhandler initMethod invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
                }
            }
            if (xxlJob.destroy().trim().length() > 0) {
                try {
                    destroyMethod = bean.getClass().getDeclaredMethod(xxlJob.destroy());
                    destroyMethod.setAccessible(true);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("xxl-job method-jobhandler destroyMethod invalid, for[" + bean.getClass() + "#" + executeMethod.getName() + "] .");
                }
            }

            // registry jobhandler
            registJobHandler(name, new MethodJobHandler(bean, executeMethod, initMethod, destroyMethod));
        }
    }

image.png

image.png

image.png 这样子就注册完成了

二.执行原理

image.png 当我们在调度中心执行任务后,调度中心就会调用执行器项目的com.xxl.job.core.handler.impl.MethodJobHandler#execute方法

image.png method就是注解@XxlJob修饰的方法demoJobHandler(),这样子就执行到对应的方法demoJobHandler里面的逻辑

image.png