Как создать и впоследствии получить доступ к ресурсу уровня приложения?

Изменить: я пытаюсь создать пул соединений с общей базой данных для всех сеансов веб-приложения. В другом посте говорилось, что лучший способ создать объект контекста сервлета - создать его для прослушивателя init. Однако мне неясно, как сделать этот объект доступным для использования моим сервлетом.

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.
     }
 }

Примечание: это потокобезопасно, так как инициализация статического блока безопасна.

Я предупреждаю вас заранее, то, что вы описываете, имеет некоторый запах кода, и я подозреваю, что вы сделаете лучше, чтобы полностью избежать этого паттерна. Статический ресурс, который зависит от внешнего состояния среды выполнения, нарушает все виды передовых методов работы с переменной областью.


Однако то, что вы описываете, лучше всего реализовать 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 Вы определяете с помощью этого вызова предотвращает дублирование обработки.

Что-то вроде:

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>();
    }
}; 
Другие вопросы по тегам