reactor-core/src/main/java/reactor/core/publisher/Hooks.java
public static void onLastOperator(String key, Function<? super Publisher<Object>, ? extends Publisher<Object>> onLastOperator) {
		Objects.requireNonNull(key, "key");
		Objects.requireNonNull(onLastOperator, "onLastOperator");
		log.debug("Hooking onLastOperator: {}", key);

		synchronized (log) {
			onLastOperatorHooks.put(key, onLastOperator);
			onLastOperatorHook = createOrUpdateOpHook(onLastOperatorHooks.values());
		}
	}
public static void onLastOperator(String key, Function<? super Publisher<Object>, ? extends Publisher<Object>> onLastOperator) {
		Objects.requireNonNull(key, "key");
		Objects.requireNonNull(onLastOperator, "onLastOperator");
		log.debug("Hooking onLastOperator: {}", key);

		synchronized (log) {
			onLastOperatorHooks.put(key, onLastOperator);
			onLastOperatorHook = createOrUpdateOpHook(onLastOperatorHooks.values());
		}
	}
Add or replace a named {@link Publisher} operator interceptor for the last operator created
in every flow ({@link Flux} or {@link Mono}). The passed function is applied
to the original operator {@link Publisher} and can return a different {@link Publisher},
on the condition that it generically maintains the same data type as the original.
Use of the {@link Flux}/{@link Mono} APIs is discouraged as it will recursively
call this hook, leading to {@link StackOverflowError}.
<p>
Note that sub-hooks are cumulative. Invoking this method twice with the same key will
replace the old sub-hook with that name, but keep the execution order (eg. A-h1, B-h2,
A-h3 will keep A-B execution order, leading to hooks h3 then h2 being executed).
Removing a particular key using {@link #resetOnLastOperator(String)} then adding it
back will result in the execution order changing (the later sub-hook being executed
last). Can be fully reset via {@link #resetOnLastOperator()}.
<p>
This pointcut function cannot make use of {@link Flux}, {@link Mono} or
{@link ParallelFlux} APIs as it would lead to a recursive call to the hook: the
operator calls would effectively invoke onEachOperator from onEachOperator.

@param key the key for the sub-hook to add/replace
@param onLastOperator the sub-hook: a function to intercept last operation call
(e.g. {@code map(fn2)} in {@code flux.map(fn).map(fn2).subscribe()})

@see #onLastOperator(Function)
@see #resetOnLastOperator(String)
@see #resetOnLastOperator()
@see #onEachOperator(String, Function)