Статьи

EJB 3.x: модели жизненного цикла и параллелизма (часть 1)

Сведения о жизненном цикле Java EE и деталях, связанных с параллелизмом, могут быть не новы для опытных профессионалов, но для новичков это может занять некоторое время.

совпадение

Что касается EJB, понимание их жизненного цикла (и связанных сценариев параллелизма) крайне важно для обеспечения надлежащего использования и разработки решения с использованием EJB. Злоупотреблять ими легко!

боб жизненный цикл

Жизненный цикл бобов

Я быстро расскажу о бинах без гражданства и о состоянии в этом посте и пока пропущу бобы Лимы.

  • Stateful Session Beans — жизненный цикл + обработка параллелизма
  • Бины без сохранения состояния — только модель параллелизма, поскольку я кратко рассмотрел жизненный цикл в одной из моих предыдущих публикаций .

Каковы различные состояния в жизненном цикле сессионного компонента с состоянием?

  • Не существует
  • готовы
  • Пассивированная

Как меняются штаты? Что их вызывает?

Вот быстрый снимок в виде таблицы и диаграмма высокого уровня. Для более подробной информации читайте дальше. , ,

без гражданства, EJB-жизненный цикл

Диаграмма состояний жизненного цикла бина сеанса без сохранения состояния

Примечание : 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();
    }
 
}
sfsb-JMeter-1

HTTP GET request via JMeter

sfsb-JMeter-2

Concurrent request simulation via JMeter

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
sfsb-результат

Console logs

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
SLSB-результат

Console logs

That’s all for now! I am planning to cover Singleton Session beans in a future post. Stay tuned . . . .