Я хотел бы выполнить следующий код JAVA только один раз при входе на страницу welcome.jsp.
welcome.jsp:
<%WeeklyScheduledMail wsm = WeeklyScheduledMail.INSTANCE;
wsm.startThread(); %>
Таким образом, если пользователь получает доступ к веб-сайту после запуска сервера, этот код можно использовать один раз, а другие пользователи, которые входят в систему и получают доступ к welcome.jsp, не будут выполнять этот код JAVA.
Сначала я попытался реализовать паттерн Синглтон с помощью enum, я думал, что этого будет достаточно, но это не сработало. Я также пробовал использовать ключевое слово Synchronized для методов, но ничего ...
Я уверен, что сделал что-то не так или есть лучший способ делать то, что я хочу делать.
Некоторые части кода:
WeeklyScheduledMail.java:
public enum WeeklyScheduledMail{
INSTANCE;
public void startThread() {
ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
Runnable task = new TaskSendEmail();
int initialDelay = 0;
int periodicDelay = 10;
scheduler.scheduleAtFixedRate(task, initialDelay, periodicDelay,
TimeUnit.SECONDS);
}
}
TaskSendEmail.java:
public class TaskSendEmail implements Runnable{
public void run() {
System.out.println("Hello: "+System.currentTimeMillis());
}
}
Не кажется хорошей идеей управлять такими функциями из JSP, это следует делать при запуске приложения.
@daniu Я тоже так думаю, но мне нужно «активировать» этот Java-код, когда какой-то пользователь с определенной ролью (администратор) получает доступ к странице welcome.jsp.
@Arvind Интересно! Не могли бы вы немного проиллюстрировать процесс? Это не обязательно должно быть в моем коде, просто более развернутый пример, чтобы понять, как его реализовать.
@Gera, пожалуйста, обратитесь к сообщению stackoverflow.com/a/50129252/2575725 на самом деле делает то же самое
Вы столкнулись с неправильной концепцией запуска кода инициализации приложения. JSP и другие ресурсы, доступные пользователю, не предназначены для этого. Даже если вы можете использовать некоторую ленивую логику инициализации, накладных расходов все равно можно будет избежать.
То, что вы ищете, предоставляется JavaEE: слушатель контекста, который вызывается один раз при запуске приложения, чтобы уведомить ваше приложение о том, что контекст был инициализирован:
public class MyContextListener implements javax.servlet.ServletContextListener {
private static fWeeklyScheduledMail wsm =
weeklyScheduledMail.INSTANCE;
@Override
public void contextInitialized(ServletContextEvent sce) {
wsm.startThread();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
wsm.stopThread();
}
}
Затем этот слушатель должен быть зарегистрирован в дескрипторе развертывания web.xml
(под web-app
):
<listener>
<listener-class>my.packg.MyContextListener</listener-class>
</listener>
Приведенный выше код и конфигурация заставят ваше расписание запускаться один раз при запуске приложения.
Оно работает! Большое спасибо. Но я хотел бы знать, можно ли выполнять аналогичные задачи (один поток или несколько потоков), если произойдет какое-то конкретное событие. Слушатель инициализирует поток при запуске сервера, но ... что, если я хочу, чтобы поток был инициализирован после того, как в веб-приложении произойдет определенное событие?
@Gera Какого типа другие мероприятия?
т.е. когда пользователь с ролью администратора нажимает кнопку внутри определенной страницы.
@Gera Нет, для этого можно использовать "события". Для этого следует использовать обычный код приложения (сервлет `doXyz1, прослушиватель JSF и т. д.). У вас также есть прослушиватели событий для пользовательских сеансов, но ни один прослушиватель не предназначен для обработки взаимодействия с пользователем.
Попробуйте событие Webapplication, то есть
contextInitialized()
, оно запустится только один раз.