Created
November 15, 2018 23:11
-
-
Save flying3615/ae6262dfb39680ec97f46c3c05ee0477 to your computer and use it in GitHub Desktop.
Spring @aysnc approch via JDK dynamic proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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