Сведения о жизненном цикле Java EE и деталях, связанных с параллелизмом, могут быть не новы для опытных профессионалов, но для новичков это может занять некоторое время.
Что касается EJB, понимание их жизненного цикла (и связанных сценариев параллелизма) крайне важно для обеспечения надлежащего использования и разработки решения с использованием EJB. Злоупотреблять ими легко!
Я быстро расскажу о бинах без гражданства и о состоянии в этом посте и пока пропущу бобы Лимы.
- Stateful Session Beans — жизненный цикл + обработка параллелизма
- Бины без сохранения состояния — только модель параллелизма, поскольку я кратко рассмотрел жизненный цикл в одной из моих предыдущих публикаций .
Каковы различные состояния в жизненном цикле сессионного компонента с состоянием?
- Не существует
- готовы
- Пассивированная
Как меняются штаты? Что их вызывает?
Вот быстрый снимок в виде таблицы и диаграмма высокого уровня. Для более подробной информации читайте дальше. , ,
Примечание : DNE — не существует, R — готово, P — пассивировано, SFSB — сессионный компонент с сохранением состояния
Государственный переход | Триггеры | Callbacks |
---|---|---|
DNE к R | При первом обращении к экземпляру SFSB через JNDI или DI | @PostConstruct |
R в DNE | Контейнер завершает работу, клиент вызывает метод, аннотированный @Remove, компонент достигает порога простоя, обозначенного DD или @StatefulTimeout | @PreDestroy |
R к P | Контейнер EJB пассивирует неиспользуемые компоненты и удаляет их из активной памяти на основе определенных алгоритмов. | @PrePassivate |
P к DNE | Компонент достигает порога простоя, обозначенного DD или @StatefulTimeout | Примечание : аннотированный метод @PreDestroy НЕ вызывается |
P к R | Когда клиент вызывает экземпляр SFSB после его пассивации, но время еще не истекло | @PostActivate |
Примечание . Если SFSB выдает исключение во время обработки запроса, его экземпляр уничтожается, т.е. он переходит в состояние DNE. В этом случае аннотированный метод @PreDestroy не вызывается
Теперь, когда у нас есть некоторое представление о жизненном цикле SFSB, давайте попробуем взглянуть на то, как эти бины ведут себя под нагрузкой, т.е. когда приложение используется несколькими пользователями одновременно, что приводит к одновременному доступу экземпляров SFSB.
Сессионные компоненты Stateful: управление параллелизмом
Безопасность потоков — одна из основных функций EJB. Следует отметить, что эта безопасность потока бесплатна и не требует каких-либо связанных с параллелизмом конструкций, которые должны быть закодированы самим разработчиком компонента (есть несколько исключений ). Что касается SFSB, контейнер EJB гарантирует, что только один поток может получить доступ к экземпляру компонента в определенный момент времени.
В этом примере мы пытаемся симулировать одновременный доступ к одному экземпляру SFSB, вызывая тестовый сервлет через JMeter . Сервлет вводит компонент через DI и вызывает для него метод. Метод SFSB просто использует Thread.sleep (), чтобы притворяться, будто он что-то выполняет.
package com.abhirockzz.wordpress.ejb.lifecycle.stateful; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.Stateful; @Stateful public class MyStatefulBean { public MyStatefulBean() { } public void act() { System.out.println("Entered MyStatefulBean/act() on " + new Date().toString() + " . SFSB instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException ex) { Logger.getLogger(MyStatefulBean.class.getName()).log(Level.SEVERE, null, ex); } System.out.println("Exit MyStatefulBean/act() on " + new Date().toString() + " . SFSB instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName()); } }
package com.abhirockzz.wordpress.ejb.lifecycle.stateful; import java.io.IOException; import java.util.Date; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name = "SFSBTestServlet", urlPatterns = {"/SFSBTestServlet"}) public class SFSBTestServlet extends HttpServlet { public SFSBTestServlet() { } @Inject MyStatefulBean mySFSB; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Entered SFSBTestServlet/doGet() on " + new Date().toString() + " . Servlet instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName()); mySFSB.act(); } }package com.abhirockzz.wordpress.ejb.lifecycle.stateful; import java.io.IOException; import java.util.Date; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name = "SFSBTestServlet", urlPatterns = {"/SFSBTestServlet"}) public class SFSBTestServlet extends HttpServlet { public SFSBTestServlet() { } @Inject MyStatefulBean mySFSB; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Entered SFSBTestServlet/doGet() on " + new Date().toString() + " . Servlet instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName()); mySFSB.act(); } }
Observations
- Since a Servlet itself is not thread safe, multiple threads will in fact enter the doGet() method
- A single instance of the SFSB (evident via the hashCode result) in being accessed concurrently (see the thread names in the logged statements)
- Only one thread will be able to access the SFSB instance though – other threads wait for their turn while the SFSB method returns. This delay is noticeable via the log statements on the console
What about Stateless Beans?
Эти бобы по своей природе являются
потокобезопасными .
Почему ? Это связано с тем, что по умолчанию контейнер обеспечивает обслуживание
каждого нового запроса новым экземпляром компонента. Помните, что клиент может получить ссылку на bean-компонент без состояния тремя возможными способами — DI, JNDI или через удаленный интерфейс (RMI). Во всех этих случаях это контейнер (прокси), который перехватывает вызов — таким образом, даже если несколько потоков, по-видимому, обращаются к одному и тому же экземпляру компонента, на самом деле он не совпадает.
package com.abhirockzz.wordpress.ejb.lifecycle.stateless; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.Stateless; @Stateless public class MyStatelesslBean { public void act() { System.out.println("Entered MyStatelesslBean/act() on " + new Date().toString() + " . SLSB instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException ex) { Logger.getLogger(MyStatelesslBean.class.getName()).log(Level.SEVERE, null, ex); } System.out.println("Exit MyStatelesslBean/act() on " + new Date().toString() + " . SLSB instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName()); } }
package com.abhirockzz.wordpress.ejb.lifecycle.stateless; import java.io.IOException; import java.util.Date; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name = "SLSBTestServlet", urlPatterns = {"/SLSBTestServlet"}) public class SLSBTestServlet extends HttpServlet { @Inject MyStatelesslBean slsb; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Entered SLSBTestServlet/doGet() on " + new Date().toString() + " . Servlet instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName()); slsb.act(); } }
Observations
- Since a Servlet itself is not thread safe, multiple threads will in fact enter the doGet() method
- Different instances of the SLSB (evident via the hashCode result) are being picked by the container to manage concurrent requests (see the thread names in the logged statements).
- In spite of concurrent requests, each request thread is getting serviced by a new instance
That’s all for now! I am planning to cover Singleton Session beans in a future post. Stay tuned . . . .