Edit: I am trying to create a shared database connection pool for all sessions of a web application. A different post said the best way to create a servlet context object was by having the init listener create it. I am however unclear on how to make this object available for use by my servlet.
How do you create and later access an application level resource?
250 views Asked by user3056052 AtThere are 5 answers
Another way you could do this is use static initialization:
public class SomeClass {
private static final Object[] CONTENT;
static {
CONTENT = new Object[SomeOtherClass.getContentSize()]; // To show you can access runtime variables
}
}
This will initialize the CONTENT
array once the class is loaded using the ClassLoader.
Something like:
public static abstract class Lazy<T> {
private T t = null;
public synchronized T get() {
if (t == null) {
t = create();
}
return t;
}
protected abstract T create();
}
public static final Lazy<List<String>> lazyList = new Lazy<List<String>>(){
@Override
protected List<String> create() {
return new ArrayList<String>();
}
};
I'll caution you up front, what you're describing has a bit of code smell, and I suspect you'll do better to avoid this pattern entirely. A static resource that depends on external runtime state breaks all sorts of best practices about variable scope.
What you're describing, however, would best be implemented by either a Supplier
or a Future
, depending on the work involved in successfully constructing the object you need. The difference is somewhat pedantic, but you'd generally use a Future
to hold a reference that will take a long time to compute, while a Supplier
generally returns quickly. Future
also has some nice hook-ins with Java's concurrency utilities, but by the sound of it you don't need that.
You'd use a Supplier
like so:
public class GlobalState {
public static final Supplier<LazyData> MY_DATA = Suppliers.memoize(
new Supplier<LazyData>() {
public LazyData get() {
// do whatever you need to construct your object, only gets executed once needed
}
});
...
}
Suppliers.memoize()
will cache the result of the first call to the underlying Supplier
in a threadsafe way, so simply wrapping the Supplier
you define with this call prevents duplicate processing.
The simplest lazy initialisation is to use an enum
with one instance.
enum Singleton {
INSTANCE; // lazy initialised
}
The added problem is you want initialisation values. To handle this you can nest the class.
enum Utility {;
static MyType val;
static OtherType val2;
enum Holder {
INSTANCE;
Holder() {
// uses val and val2
}
}
public static Holder getInstance(MyType val, OtherType val2) {
Utility.val = val;
Utility.val2 = val2;
return Holder.INSTANCE; // only created the first time.
}
}
Note: this is thread safe as static block initialisation is safe.
One solution is using a private holder class:
the instance will be initialized when
SomeClass.getInstance()
is called the first time.