Skip to content

Instantly share code, notes, and snippets.

@flying3615
Created November 15, 2018 23:11
Show Gist options
  • Save flying3615/ae6262dfb39680ec97f46c3c05ee0477 to your computer and use it in GitHub Desktop.
Save flying3615/ae6262dfb39680ec97f46c3c05ee0477 to your computer and use it in GitHub Desktop.
Spring @aysnc approch via JDK dynamic proxy
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class JdkProxySpringAsyncDemo {
interface If {
String originalMethod(String s);
@InAsync(value = ExecutorType.CACHED)
Future<String> originalMethodAsync(String s);
}
static class AsyncRes<T> implements Future<T> {
T value;
AsyncRes(T result) {
this.value = result;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return false;
}
@Override
public T get() throws InterruptedException, ExecutionException {
return value;
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return get();
}
}
static class Original implements If {
@Override
public String originalMethod(String s) {
return "Original " + s;
}
@Override
public Future<String> originalMethodAsync(String s) {
return new AsyncRes<>("Original " + s + " in "+Thread.currentThread().getName());
}
}
static class Handler implements InvocationHandler {
private final If original;
Handler(If original) {
this.original = original;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before execution...");
InAsync inAsync = method.getAnnotation(InAsync.class);
Object invokeResult;
if (Objects.nonNull(inAsync)) {
ExecutorType executorType = inAsync.value();
Executor executor;
switch (executorType) {
case CACHED:
executor = Executors.newCachedThreadPool();
break;
case FOLKJOIN:
executor = new ForkJoinPool();
break;
default:
executor = Executors.newSingleThreadExecutor();
}
Callable<Object> task = () -> {
try {
Object result = method.invoke(original, args);
if (result instanceof Future) {
return ((Future<?>)result).get();
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
((ExecutorService) executor).shutdown();
}
return null;
};
invokeResult = ((ExecutorService) executor).submit(task);
} else {
invokeResult = method.invoke(original, args);
}
System.out.println("End execution...");
return invokeResult;
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Original original = new Original();
Handler handler = new Handler(original);
If f = (If) Proxy.newProxyInstance(If.class.getClassLoader(), new Class[]{If.class}, handler);
String str = f.originalMethod("Hallo");
System.out.println("result from proxy "+str);
Future<String> future = f.originalMethodAsync("Hallooooo");
System.out.println("result from proxy in future " + future.get());
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface InAsync {
ExecutorType value() default ExecutorType.SINGLETHREAD;
}
enum ExecutorType {
SINGLETHREAD,
CACHED,
FOLKJOIN
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment