flink深入研究(02) flink運行環境的獲取(上)

// 獲取運行環境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

這行代碼會返回一個可用的執行環境,是flink程序執行的上下文,記錄了相關配,如並行度等,並提供了一系列方法,如輸入流的讀入方法,運行整個程序的execute方法等,對於分步式流處理程序來說,flatMap,keyBy等等操作,都可以理解爲一種聲明,告訴整個程序採用了什麼樣的算子(這段文字參考自https://www.cnblogs.com/bethunebtj/p/9168274.html),接下來我們開始進入到代碼內部,看看運行環境的獲取過程。

代碼講解

我們開始看代碼:

/**
	 * Creates an execution environment that represents the context in which the
	 * program is currently executed. If the program is invoked standalone, this
	 * method returns a local execution environment, as returned by
	 * {@link #createLocalEnvironment()}.
	 *
	 * @return The execution environment of the context in which the program is
	 * executed.
	 */
	public static StreamExecutionEnvironment getExecutionEnvironment() {
		return Utils.resolveFactory(threadLocalContextEnvironmentFactory, contextEnvironmentFactory)
			.map(StreamExecutionEnvironmentFactory::createExecutionEnvironment)
			.orElseGet(StreamExecutionEnvironment::createStreamExecutionEnvironment);
	}

其中threadLocalContextEnvironmentFactory的定義如下:

/** The ThreadLocal used to store {@link StreamExecutionEnvironmentFactory}. */
private static final ThreadLocal<StreamExecutionEnvironmentFactory> threadLocalContextEnvironmentFactory = 
new ThreadLocal<>();

可以看到這是一個ThreadLocal<T>類,這個類用來將變量存儲在對應的線程緩存中,主要用到了ThreadLocalMap類,這個類每一個線程類都會維護,變量名稱是threadLocals,這是一個map容器,線程的緩存數據存放在這個map中。ThreadLocalMap採用的是數組式存儲,而HashMap採用的是拉鍊式存儲,兩者是不同的,感興趣可以去看看源碼,這裏不做詳細分析。

contextEnvironmentFactory變量定義代碼如下

/**
	 * The environment of the context (local by default, cluster if invoked through command line).
	 */
	private static StreamExecutionEnvironmentFactory contextEnvironmentFactory = null;

 

resolveFactory函數,代碼如下:

/**
	 * Resolves the given factories. The thread local factory has preference over the static factory.
	 * If none is set, the method returns {@link Optional#empty()}.
	 *
	 * @param threadLocalFactory containing the thread local factory
	 * @param staticFactory containing the global factory
	 * @param <T> type of factory
	 * @return Optional containing the resolved factory if it exists, otherwise it's empty
	 */
	public static <T> Optional<T> resolveFactory(ThreadLocal<T> threadLocalFactory, @Nullable T staticFactory) {
        //從線程緩存中獲取localFactory
		final T localFactory = threadLocalFactory.get();
        //如果線程緩存中沒有找到那麼就採用staticFactory
		final T factory = localFactory == null ? staticFactory : localFactory;
        //創建Optional類對象,值爲facory(這裏facory爲null會拋出異常)
		return Optional.ofNullable(factory);
	}

map函數,代碼如下:

/**
     * If a value is present, apply the provided mapping function to it,
     * and if the result is non-null, return an {@code Optional} describing the
     * result.  Otherwise return an empty {@code Optional}.
     *
     * @apiNote This method supports post-processing on optional values, without
     * the need to explicitly check for a return status.  For example, the
     * following code traverses a stream of file names, selects one that has
     * not yet been processed, and then opens that file, returning an
     * {@code Optional<FileInputStream>}:
     *
     * <pre>{@code
     *     Optional<FileInputStream> fis =
     *         names.stream().filter(name -> !isProcessedYet(name))
     *                       .findFirst()
     *                       .map(name -> new FileInputStream(name));
     * }</pre>
     *
     * Here, {@code findFirst} returns an {@code Optional<String>}, and then
     * {@code map} returns an {@code Optional<FileInputStream>} for the desired
     * file if one exists.
     *
     * @param <U> The type of the result of the mapping function
     * @param mapper a mapping function to apply to the value, if present
     * @return an {@code Optional} describing the result of applying a mapping
     * function to the value of this {@code Optional}, if a value is present,
     * otherwise an empty {@code Optional}
     * @throws NullPointerException if the mapping function is null
     */
    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        //斷言,如果mapper爲null就拋出異常
        Objects.requireNonNull(mapper);
        if (!isPresent())
            //如果當前的Optional類對象的value變量值爲null,那麼就返回一個成員變量value爲null的Optional類對象
            return empty();
        else {
            //否則創建一個StreamExecutionEnvironment類對象同時創建一個Optional類對象
            return Optional.ofNullable(mapper.apply(value));
        }
    }

orElseGet函數,代碼如下:

/**
     * Return the value if present, otherwise invoke {@code other} and return
     * the result of that invocation.
     *
     * @param other a {@code Supplier} whose result is returned if no value
     * is present
     * @return the value if present otherwise the result of {@code other.get()}
     * @throws NullPointerException if value is not present and {@code other} is
     * null
     */
    public T orElseGet(Supplier<? extends T> other) {
        //如果value不爲null那麼就採用value,否則採用other.get()
        return value != null ? value : other.get();
    }

總結一下,flink中獲取環境變量的步驟是:

1、先從本地線程緩存中獲取實現StreamExecutionEnvironmentFactory接口的類對象,如果沒有那麼採用contextEnvironmentFactory變量,並將該類對象封裝在Optional類對象中,返回一個value爲StreamExecutionEnvironmentFactory接口類對象的OPtional類對象---------resolveFactory函數

2、然後調用Optional類對象的map函數,如果在1中創建了StreamExecutionEnvironmentFactory接口的類對象,那麼就調用該接口類對象的createExecutionEnvironment函數創建StreamExecutionEnvironment類對象,如果1中StreamExecutionEnvironmentFactory接口的類對象爲null,那麼就封裝一個value爲null的Optional類對象,返回一個value爲StreamExecutionEnvironment類對象的Optional類對象-----------map函數

3、如果上面沒有獲取到StreamExecutionEnvironment類對象,那麼就調用StreamExecutionEnvironment類中的靜態函數createStreamExecutionEnvironment來獲取StreamExecutionEnvironment類對象--------orElseGet函數

createStreamExecutionEnvironment函數代碼如下:

private static StreamExecutionEnvironment createStreamExecutionEnvironment() {
		// because the streaming project depends on "flink-clients" (and not the other way around)
		// we currently need to intercept the data set environment and create a dependent stream env.
		// this should be fixed once we rework the project dependencies

		ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
		if (env instanceof ContextEnvironment) {
			return new StreamContextEnvironment((ContextEnvironment) env);
		} else if (env instanceof OptimizerPlanEnvironment || env instanceof PreviewPlanEnvironment) {
			return new StreamPlanEnvironment(env);
		} else {
			return createLocalEnvironment();
		}
	}

createStreamExecutionEnvironment函數我們下篇繼續,看看它裏面做了些什麼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章