Как инициализировать API в среде сервлетов

Очевидно, я хочу написать разделенные компоненты. Одна часть - это движок форм. Я не хочу, чтобы он зависел от API сервлета, но я должен инициализировать его для каждого запроса (или, по крайней мере, для каждого сеанса).

В приложении я бы использовал что-то вроде

public static void setLocale(Locale l);

тогда мои отдельные классы могли бы получить это со статическим получателем. Это невозможно в среде сервлетов (сервлетам не хватает даже static getServletContext() метод, через который можно эмулировать статическое поведение).

Я абсолютно не хочу использовать фабрику (у меня будет более 10 классов, каждый из которых будет использовать некоторую конфигурацию, по крайней мере, Locale) или что-то еще хуже: создайте каждый объект с помощью блока параметров (который содержит Locale и другие настройки).

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

Если любая другая возможность не удалась, я подумал об использовании чего-то вроде

class MyParameters {
    private Map<Thread, MyParameters> threadParameters = new Map<Thread, MyParameters>();

    public static void setParameters(MyParameters parameters) {
        threadParameters.put(Thread.getCurrentThread(), parameters);
    }

    public static MyParameters getParameters() {
        return threadParameters.get(Thread.getCurrentThread());
    }    
}

... но это создает некоторые проблемы безопасности (сервлет может не инициализировать его и использовать значения, установленные во время предыдущего запроса, обслуживаемого тем же потоком). - Хотя использование локали другого пользователя не представляет особой угрозы.

2 ответа

Решение

но я должен инициализировать его для каждого запроса (или, по крайней мере, для каждого сеанса).

Использовать Filter, HttpServlet или же ServletRequestListener (или HttpSessionListener).

но это создает некоторые проблемы безопасности

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

Лучше всего создать ThreadLocal<T> учебный класс. Предполагая, что вы хотите, чтобы он основывался на запросах / ответах, вот следующий пример:

public final class Context {

    private static ThreadLocal<Context> instance = new ThreadLocal<Context>();

    private HttpServletRequest request;
    private HttpServletResponse response;

    private Context(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
    }

    public static Context getInstance() {
        return instance.get();
    }

    public static Context newInstance(HttpServletRequest request, HttpServletResponse response) {
        Context context = new Context(request, response);
        instance.set(context);
        return context;
    }

    public void release() {
        instance.remove();
    }

    // ...
}

Получить и установить его в Filter,

Context context = null;
try {
    context = Context.newInstance(request, response);
    chain.doFilter(request, response);
} finally {
    if (context != null) context.release();
}

(обратите внимание, что очень важно выпустить контекст в finally блок из try блок, где вы его получаете, иначе он не будет освобожден, когда обработка запроса-ответа выдает исключение)

Наконец, вы можете получить его везде в своем коде следующим образом:

Context context = Context.getInstance();
context.setLocale(locale); 
Locale foo = context.getLocale();
// ...

где вы делегируете методы местному request и / или response переменные.

Обратите внимание, что подобная конструкция уже существует в некоторых средах MVC, таких как JSF с ее FacesContext, Вместо того, чтобы выращивать один дом, вы бы хотели посмотреть, не там ли трава зеленее.

Вы также можете рассмотреть возможность использования моего подхода, который обсуждается здесь: Вопрос о дизайне JSP/ сервлета - Сделать запрос / ответ глобально доступным через JNDI

В моем подходе объекты запроса и ответа хранятся в JNI вместо ThreadLocal. Кроме того, их настройка и очистка выполняются в фильтре, как описано выше...

Другие вопросы по тегам