Created
April 4, 2019 14:20
-
-
Save fmarot/4d83f06c9aac1a8d77e1fca76f77aa90 to your computer and use it in GitHub Desktop.
This class contains a builder method that allows to create object with time-consuming constructor in background. Then it can be used as usual from a user perspective. Totally trensparent from user-side apart the construction using the provided builder method.
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
package com.oleamedical.dbclient.sds; | |
import java.lang.reflect.InvocationHandler; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Proxy; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
import java.util.concurrent.Future; | |
import java.util.concurrent.ThreadFactory; | |
import java.util.function.Supplier; | |
import com.google.common.util.concurrent.ThreadFactoryBuilder; | |
import lombok.extern.slf4j.Slf4j; | |
/** This class contains a builder method that allows to create object with time-consuming constructor in background. | |
* It allows the callers to use the object as if it was a real object, method will block until initialization is done. | |
* Use sample: | |
* Getcoucou object = buildInBackground(() -> new LongCtor(), Getcoucou.class); | |
* ... // some code not using the resulting object | |
* object.coucou(); // use object as usual, will block if object is not already fully created | |
* | |
* Remark: we could use Bytebuddy or CGLib to be able to use with concrete class instead of forcing to use an interface | |
* */ | |
@Slf4j | |
public class BackgroundObjectBuilder implements InvocationHandler { | |
private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() | |
.setNameFormat(BackgroundObjectBuilder.class + "-%d").setUncaughtExceptionHandler((thread, ex) -> log.error("", ex)).build(); //$NON-NLS-1$ | |
private static ExecutorService threadPool = Executors.newFixedThreadPool(3, namedThreadFactory); | |
private Future<Object> builtObject; | |
static <T> T buildInBackground(Supplier<T> supplier, Class<T> interfaze) { | |
Future<Object> builtObject = threadPool.submit(() -> supplier.get()); | |
T proxy = (T) Proxy.newProxyInstance( | |
interfaze.getClassLoader(), | |
new Class[] { interfaze }, | |
new BackgroundObjectBuilder(builtObject)); | |
return proxy; | |
} | |
private BackgroundObjectBuilder(Future<Object> builtObject) { | |
this.builtObject = builtObject; | |
} | |
@Override | |
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |
return method.invoke(builtObject.get(), args); | |
} | |
public static void main(String[] args) throws InterruptedException { | |
log.info("before"); | |
new LongCtor().getCoucou(); | |
log.info("after 1st"); | |
Getcoucou object = buildInBackground(() -> new LongCtor(), Getcoucou.class); | |
object.getCoucou(); | |
log.info("after second"); | |
} | |
interface Getcoucou { | |
public String getCoucou(); | |
} | |
static class LongCtor implements Getcoucou { | |
public LongCtor() { | |
log.info("creating..."); | |
try { | |
Thread.sleep(5000); | |
} catch (InterruptedException e) { | |
log.error("", e); | |
} | |
log.info("creation done..."); | |
} | |
@Override | |
public String getCoucou() { | |
return "Coucou :)"; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment