flink 任务执行类的加载

执行具体任务的TaskManager在要执行向相应的具体的任务之前,都是通过submitTask()方法得到具体所要执行的任务的。

在submitTask()中,部署的任务信息并不包含具体所要执行的目标任务类jar包。

 

所要任务的抽象是Task类。其实现了Runnnable接口,自然提供了run()方法可提供给线程进行调用。在其构造方法中,以自身为target作为Thread构造函数的参数,得到可执行的线程对象。

executingThread = new Thread(TASK_THREADS_GROUP, this, taskNameWithSubtask);

但是在Task()的构造方法中,并没有直接直接执行开始线程的调用,而是在submitTask()方法中调用了startTaskThread()方法。

public void startTaskThread() {
   executingThread.start();
}

在这时,才是开始了Task的run()方法。

在Task()的构造方法,只给出了job的执行类名和和blob类型的jar包名和classpath名,在Task的run()方法中,也将根据这些信息加载得到目标任务的实现类并执行。

首先,会通过createUserCodeClassLoader()方法去得到目标任务类的类加载器。

userCodeClassLoader = createUserCodeClassloader();

private ClassLoader createUserCodeClassloader() throws Exception {
   long startDownloadTime = System.currentTimeMillis();

   // triggers the download of all missing jar files from the job manager
   libraryCache.registerTask(jobId, executionId, requiredJarFiles, requiredClasspaths);

   LOG.debug("Getting user code class loader for task {} at library cache manager took {} milliseconds",
         executionId, System.currentTimeMillis() - startDownloadTime);

   ClassLoader userCodeClassLoader = libraryCache.getClassLoader(jobId);
   if (userCodeClassLoader == null) {
      throw new Exception("No user code classloader available.");
   }
   return userCodeClassLoader;
}

在这个方法中涉及到了libraryCache。

libraryCache是一个LiberaryCacheManager类型的对象,用来缓存下载得到的目标jar包,具体实现类为BlobLibraryCacheManager。

@Override
public void registerTask(
   JobID jobId,
   ExecutionAttemptID task,
   @Nullable Collection<PermanentBlobKey> requiredJarFiles,
   @Nullable Collection<URL> requiredClasspaths) throws IOException {

   checkNotNull(jobId, "The JobId must not be null.");
   checkNotNull(task, "The task execution id must not be null.");

   if (requiredJarFiles == null) {
      requiredJarFiles = Collections.emptySet();
   }
   if (requiredClasspaths == null) {
      requiredClasspaths = Collections.emptySet();
   }

   synchronized (lockObject) {
      LibraryCacheEntry entry = cacheEntries.get(jobId);

      if (entry == null) {
         URL[] urls = new URL[requiredJarFiles.size() + requiredClasspaths.size()];
         int count = 0;
         try {
            // add URLs to locally cached JAR files
            for (PermanentBlobKey key : requiredJarFiles) {
               urls[count] = blobService.getFile(jobId, key).toURI().toURL();
               ++count;
            }

            // add classpaths
            for (URL url : requiredClasspaths) {
               urls[count] = url;
               ++count;
            }

            cacheEntries.put(jobId, new LibraryCacheEntry(
               requiredJarFiles, requiredClasspaths, urls, task, classLoaderResolveOrder, alwaysParentFirstPatterns));
         } catch (Throwable t) {
            // rethrow or wrap
            ExceptionUtils.tryRethrowIOException(t);
            throw new IOException(
               "Library cache could not register the user code libraries.", t);
         }
      } else {
         entry.register(task, requiredJarFiles, requiredClasspaths);
      }
   }
}

其中registerTask()方法,正是根据jobId检查是否已经下载得到了相应的jar包,如果没有,则需要前去下载相应的jar包,需要相应的jar包名和classpath名。

在这里新下载得到的jar包转为url作为cacheEnty的一部分,此时,针对这一部分url的类加载器也生成完毕作为cacheEntry的一部分,缓存在LiberaryCacheManager中。

 

在通过registerTask()方法确保执行任务的对应jar包下载完毕之后,根据jobid得到对应的类加载器,即可准备加载相应的任务类,执行相应的类。

回到run()方法中,通过loadAndInstantiateInvokable()方法加载并实例化目标类。

private static AbstractInvokable loadAndInstantiateInvokable(
   ClassLoader classLoader,
   String className,
   Environment environment) throws Throwable {

   final Class<? extends AbstractInvokable> invokableClass;
   try {
      invokableClass = Class.forName(className, true, classLoader)
         .asSubclass(AbstractInvokable.class);
   } catch (Throwable t) {
      throw new Exception("Could not load the task's invokable class.", t);
   }

   Constructor<? extends AbstractInvokable> statelessCtor;

   try {
      statelessCtor = invokableClass.getConstructor(Environment.class);
   } catch (NoSuchMethodException ee) {
      throw new FlinkException("Task misses proper constructor", ee);
   }

   // instantiate the class
   try {
      //noinspection ConstantConditions  --> cannot happen
      return statelessCtor.newInstance(environment);
   } catch (InvocationTargetException e) {
      // directly forward exceptions from the eager initialization
      throw e.getTargetException();
   } catch (Exception e) {
      throw new FlinkException("Could not instantiate the task's invokable class.", e);
   }
}

这里通过得到的类加载器加载相应的类,并取得envirment为参数的构造方法,通过该构造方法实例化一个类 ,作为Task中实际被调用的类的实例,接下来将准备被正是调用。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值