Support for isolated class loaders extended to cover more functions
Functions with Flux and Message (as well as POJOs and Flux of POJO which were already supported) should now work if they are created in an isolated class loader. Preconditions: * The class loaders must have the reactor-core (and reactive-streams) shared between the app and the function. Practically speaking this means there has to be a parent class loader with just reactive types, and sibling children for the app and the function. This is not a new requirement (it was needed for Flux of POJO anyway). * Message types are handled reflectively, so they don't have to be in a shared class loader. But they do have to be on the class path on both sides (obviously).
This commit is contained in:
@@ -28,7 +28,7 @@ import reactor.core.publisher.Flux;
|
||||
*
|
||||
* @param <T> input type of target consumer
|
||||
*/
|
||||
public class FluxConsumer<T> implements Consumer<Flux<T>> {
|
||||
public class FluxConsumer<T> implements Consumer<Flux<T>>, FluxWrapper<Consumer<T>> {
|
||||
|
||||
private final Consumer<T> consumer;
|
||||
|
||||
@@ -36,6 +36,11 @@ public class FluxConsumer<T> implements Consumer<Flux<T>> {
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Consumer<T> getTarget() {
|
||||
return this.consumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Flux<T> input) {
|
||||
input.subscribe(t -> consumer.accept(t));
|
||||
|
||||
@@ -29,13 +29,18 @@ import reactor.core.publisher.Flux;
|
||||
* @param <T> input type of target function
|
||||
* @param <R> output type of target function
|
||||
*/
|
||||
public class FluxFunction<T, R> implements Function<Flux<T>, Flux<R>> {
|
||||
public class FluxFunction<T, R> implements Function<Flux<T>, Flux<R>>, FluxWrapper<Function<T, R>> {
|
||||
|
||||
private final Function<T, R> function;
|
||||
|
||||
public FluxFunction(Function<T, R> function) {
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<T, R> getTarget() {
|
||||
return this.function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<R> apply(Flux<T> input) {
|
||||
|
||||
@@ -33,7 +33,7 @@ import reactor.core.publisher.Flux;
|
||||
*
|
||||
* @param <T> output type of target supplier
|
||||
*/
|
||||
public class FluxSupplier<T> implements Supplier<Flux<T>> {
|
||||
public class FluxSupplier<T> implements Supplier<Flux<T>>, FluxWrapper<Supplier<T>> {
|
||||
|
||||
private final Supplier<T> supplier;
|
||||
|
||||
@@ -42,12 +42,17 @@ public class FluxSupplier<T> implements Supplier<Flux<T>> {
|
||||
public FluxSupplier(Supplier<T> supplier) {
|
||||
this(supplier, null);
|
||||
}
|
||||
|
||||
|
||||
public FluxSupplier(Supplier<T> supplier, Duration period) {
|
||||
this.supplier = supplier;
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<T> getTarget() {
|
||||
return this.supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Flux<T> get() {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.core;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface FluxWrapper<T> {
|
||||
|
||||
T getTarget();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.core;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface Isolated {
|
||||
|
||||
ClassLoader getClassLoader();
|
||||
}
|
||||
@@ -24,18 +24,25 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class IsolatedConsumer<T> implements Consumer<T> {
|
||||
public class IsolatedConsumer<T> implements Consumer<T>, Isolated {
|
||||
|
||||
private final Consumer<T> consumer;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public IsolatedConsumer(Consumer<T> consumer) {
|
||||
this.consumer = consumer;
|
||||
this.classLoader = consumer.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return this.classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(T item) {
|
||||
ClassLoader context = ClassUtils
|
||||
.overrideThreadContextClassLoader(consumer.getClass().getClassLoader());
|
||||
.overrideThreadContextClassLoader(this.classLoader);
|
||||
try {
|
||||
consumer.accept(item);
|
||||
}
|
||||
|
||||
@@ -24,20 +24,27 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class IsolatedFunction<S, T> implements Function<S, T> {
|
||||
public class IsolatedFunction<S, T> implements Function<S, T>, Isolated {
|
||||
|
||||
private final Function<S, T> function;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public IsolatedFunction(Function<S, T> function) {
|
||||
this.function = function;
|
||||
this.classLoader = function.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return this.classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(S item) {
|
||||
ClassLoader context = ClassUtils
|
||||
.overrideThreadContextClassLoader(function.getClass().getClassLoader());
|
||||
.overrideThreadContextClassLoader(this.classLoader);
|
||||
try {
|
||||
return function.apply(item);
|
||||
return this.function.apply(item);
|
||||
}
|
||||
finally {
|
||||
ClassUtils.overrideThreadContextClassLoader(context);
|
||||
|
||||
@@ -24,18 +24,25 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class IsolatedSupplier<T> implements Supplier<T> {
|
||||
public class IsolatedSupplier<T> implements Supplier<T>, Isolated {
|
||||
|
||||
private final Supplier<T> supplier;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public IsolatedSupplier(Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
this.classLoader = supplier.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return this.classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
ClassLoader context = ClassUtils
|
||||
.overrideThreadContextClassLoader(supplier.getClass().getClassLoader());
|
||||
.overrideThreadContextClassLoader(this.classLoader);
|
||||
try {
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user