Изменить: я пытаюсь создать общий пул соединений с базой данных для всех сеансов веб-приложения. В другом сообщении говорилось, что лучший способ создать объект контекста сервлета — создать его с помощью прослушивателя инициализации. Однако я не понимаю, как сделать этот объект доступным для использования моим сервлетом.
Как вы создаете и позже получаете доступ к ресурсу уровня приложения?
Ответы (5)
Другой способ сделать это - использовать статическую инициализацию:
public class SomeClass {
private static final Object[] CONTENT;
static {
CONTENT = new Object[SomeOtherClass.getContentSize()]; // To show you can access runtime variables
}
}
Это инициализирует массив CONTENT
после загрузки класса с помощью ClassLoader.
Одним из решений является использование класса частного владельца:
public class SomeClass {
private static class ResourceHolder {
private static final Resource INSTANCE = new Resource();
}
public static Resource getInstance() {
return ResourceHolder.INSTANCE;
}
}
экземпляр будет инициализирован при первом вызове SomeClass.getInstance()
.
Самая простая ленивая инициализация — использовать enum
с одним экземпляром.
enum Singleton {
INSTANCE; // lazy initialised
}
Дополнительная проблема заключается в том, что вам нужны значения инициализации. Чтобы справиться с этим, вы можете вложить класс.
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.
}
}
Примечание: это потокобезопасно, так как инициализация статического блока безопасна.
Что-то вроде:
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>();
}
};
Я сразу предупрежу вас, что то, что вы описываете, имеет немного запаха кода, и я подозреваю, что вам лучше полностью избегать этого шаблона. Статический ресурс, зависящий от внешнего состояния среды выполнения, нарушает все передовые методы работы с областью видимости переменных.
Однако то, что вы описываете, лучше всего реализовать с помощью Supplier
или Future
, в зависимости от объема работы, необходимого для успешного создания нужного вам объекта. Разница несколько педантична, но вы обычно используете Future
для хранения ссылки, которая займет много времени для вычисления, в то время как Supplier
обычно возвращает быстро. Future
также имеет несколько хороших подключений к утилитам параллелизма Java, но, судя по всему, вам это не нужно.
Вы бы использовали Supplier
так:
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()
будет кэшировать результат первого вызова базового Supplier
потокобезопасным способом, поэтому простое обертывание Supplier
, которое вы определяете с помощью этого вызова, предотвращает дублирование обработки.