Skip to content

Instantly share code, notes, and snippets.

@fmarot
Created April 4, 2019 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fmarot/4d83f06c9aac1a8d77e1fca76f77aa90 to your computer and use it in GitHub Desktop.
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.
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