Использование специального сервлета автоматического запуска для инициализации при запуске и совместного использования данных приложения

Мне нужно получить некоторую конфигурацию и подключиться к внешним ресурсам/объектам/системам где-нибудь и сохранить ее в области приложения.

Я могу увидеть два способа настройки моего приложения:

  • Переопределение init() в существующих сервлетах и ​​требуемый код там и сохранение всех сконструированных объектов внутри этого же сервлета.
  • Наличие своего рода серфинга инициализации и использование его init() для выполнения этой работы. Затем сохраните созданные объекты в ServletContext, чтобы поделиться им с другими сервлетами.

Какой из вышеперечисленного лучше подходит? Есть ли лучший способ обмениваться объектами между сервлетами? Вызов их непосредственно друг от друга или так...?

Ответ 1

Ни один из них не лучший подход. Сервлеты намерены прослушивать HTTP-события (HTTP-запросы), а не события развертывания (запуск/выключение).


CDI/JSF/EJB недоступен? Используйте ServletContextListener

@WebListener
public class Config implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        // Do stuff during webapp startup.
    }

    public void contextDestroyed(ServletContextEvent event) {
        // Do stuff during webapp shutdown.
    }

}

Чтобы хранить и получать объекты в области приложения (чтобы все сервлеты могли обращаться к ним), используйте ServletContext#setAttribute() и #getAttribute().

Вот пример, который позволяет слушателю хранить себя в области приложения:

    public void contextInitialized(ServletContextEvent event) {
        event.getServletContext().setAttribute("config", this);
        // ...
    }

а затем получить его в сервлет:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        Config config = (Config) getServletContext().getAttribute("config");
        // ...
    }

Он также доступен в JSP EL на ${config}. Таким образом, вы можете сделать его простым bean.

Если вы еще не находитесь в Servlet 3.0 и не можете обновить и, следовательно, не можете использовать аннотацию @WebListener, вам необходимо вручную зарегистрировать ее в /WEB-INF/web.xml, как показано ниже:

<listener>
    <listener-class>com.example.Config</listener-class>
</listener>

Доступен CDI? Используйте @Observes на ApplicationScoped.class

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class Config {

    public void init(@Observes @Initialized(ApplicationScoped.class) ServletContext context) {
        // Do stuff during webapp startup.
    }

    public void destroy(@Observes @Destroyed(ApplicationScoped.class) ServletContext context) {
        // Do stuff during webapp shutdown.
    }
}

Это доступно в сервлете через @Inject. Сделайте это, если необходимо, также @Named, чтобы он был доступен через #{config} в EL.

Отмечено, что это новое с CDI 1.1. Если вы все еще на CDI 1.0 и не можете выполнить обновление, выберите другой подход.


Доступен JSF? Используйте @ManagedBean(eager=true)

import javax.faces.bean.ManagedBean
import javax.faces.bean.ApplicationScoped;

@ManagedBean(eager=true)
@ApplicationScoped
public class Config {

    @PostConstruct
    public void init() {
        // Do stuff during webapp startup.
    }

    @PreDestroy
    public void destroy() {
        // Do stuff during webapp shutdown.
    }
}

Это доступно через #{config} в EL.


Доступен EJB? Рассмотрим @Startup @Singleton

@Startup
@Singleton
public class Config {

    @PostConstruct
    public void init() {
        // Do stuff during webapp startup.
    }

    @PreDestroy
    public void destroy() {
        // Do stuff during webapp shutdown.
    }
}

Это доступно в сервлете через @EJB. Я говорю "считаю", потому что вы не должны злоупотреблять EJB ради запуска. Более того, a @Singleton по умолчанию блокирует чтение и запись и в первую очередь предназначен для транзакционных материалов, таких как планирование фоновых заданий.

См. также: