一.注册原理
1.XxlJobSpringExecutor的结构
我们打开源码里的xxl-job-core项目的类XxlJobSpringExecutor,发现这个类:
1.扩展了类XxlJobExecutor的destroy方法,用于销毁bean
2.实现了接口ApplicationContextAware的方法setApplicationContext来获取spring的应用上下文
3.实现了接口SmartInitializingSingleton的方法afterSingletonsInstantiated来初始化JobHandler Repository(这个是最核心的方法)
在Spring 的bean的生命周期里,当所有单例 bean 都初始化完成以后, Spring的IOC(容器会回调该接口的
afterSingletonsInstantiated()方法
XXL-JOB就是在这里获取到spring的bean容器里的@XxjJob修饰的方法,并注册到JobHandler Repository
里的.
下面我们来debug一下
1.启动执行器项目(客户端)
2.在initJobHandlerMethodRepositorydage打个断点,条件为bean的名字(这里以注解@XxlJob所在的类SampleXxlJob为例)
3.执行initJobHandlerMethodRepository具体逻辑
3.1获取对应的bean:sampleXxlJob
Object bean = applicationContext.getBean(beanDefinitionName);
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);
}
});
}
例子里@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));
}
}
这样子就注册完成了
二.执行原理
当我们在调度中心执行任务后,调度中心就会调用执行器项目的com.xxl.job.core.handler.impl.MethodJobHandler#execute方法
method就是注解@XxlJob修饰的方法demoJobHandler(),这样子就执行到对应的方法demoJobHandler里面的逻辑