7.20.2015

EJB @Stateful & Wildfly



Stateful Session Bean – сессионный компонент с сохранением состояния в сессии. Состояние компонента сохраняется на протяжении одной сессии, с которой вы работаете, после окончания сессии состояние теряется.  Применяя аннотацию @Stateful  к классу, мы говорим серверу приложений, что мы описывает бин с сохранением состояния. Давайте поговорим о жизненном цикле Stateful  бина,   у него может быть 3 состояния: Готов к обработке, В пассивном состоянии, Не существует. Существуют 4 аннотации для методов,  которые будут вызываться, когда бин переходит из одного состояния в другое.  Пусть создается новый бин, у него выполняется конструктор, дальше выполняется метод помеченный аннотацией @PostConstruct и бин помещается в память. Когда бин долго не используется, то он переходит в пассивное состояние, т.е. выгружается из памяти во временное хранилище - кэш, при этом выполняется метод помеченный аннотацией @PrePassivate.  Если бин находился в пассивном состоянии и его метод был вызван клиентской программой, то бин снова подгружается в память и восстанавливает свое состояние - готов к обработке, при этом будет выполнен метод с аннотацией @PostActivate. Когда бин уничтожается, то перед этим, вызывается метод помеченный аннотацией @PreDestroy. Давайте перейдемте к настройке Stateful бина в wildfly, откроем файл настройки JBOSS_HOME/Standalone/configuration/standalone.xml и найдем в нем строки:

<subsystem xmlns="urn:jboss:domain:ejb3:2.0">
            <session-bean>
                <stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
                <singleton default-access-timeout="5000"/>
            </session-bean>
 ….
            <caches>
                <cache name="simple"/> <!-- конец обработки -- >
                <cache name="distributable" aliases="passivating clustered" passivation-store-ref="infinispan"/>
            </caches>
            <passivation-stores>
                <passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
            </passivation-stores>
….
</subsystem>
….
        <subsystem xmlns="urn:jboss:domain:infinispan:2.0">
…..
            <cache-container name="ejb" aliases="sfsb" default-cache="passivation" module="org.wildfly.clustering.ejb.infinispan">
                <local-cache name="passivation" batching="true">
                    <file-store passivation="true" purge="false"/>
                </local-cache>
                <local-cache name="persistent" batching="true">
                    <file-store passivation="false" purge="false"/>
                </local-cache>
            </cache-container>
            ….
        </subsystem>

По умолчанию у Stateful бина не настроен кэш и он ссылается на заглушку simple  для того чтобы включить кэш нужно заменить название атрибутов на  distributable, смотрим на конфиг:
<subsystem xmlns="urn:jboss:domain:ejb3:2.0">
            <session-bean>
<stateful default-access-timeout="5000" cache-ref="distributable" passivation-disabled-cache-ref="distributable"/>
                <singleton default-access-timeout="5000"/>
            </session-bean>
 ….
            <caches>
                <cache name="simple"/>
                <cache name="distributable" aliases="passivating clustered" passivation-store-ref="infinispan"/>
            </caches>
            <passivation-stores>
                <passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
            </passivation-stores>
….
</subsystem>
….
        <subsystem xmlns="urn:jboss:domain:infinispan:2.0">
…..
            <cache-container name="ejb" aliases="sfsb" default-cache="passivation" module="org.wildfly.clustering.ejb.infinispan">
                <local-cache name="passivation" batching="true">
                    <file-store passivation="true" purge="false"/>
                </local-cache>
                <local-cache name="persistent" batching="true">
                    <file-store passivation="false" purge="false"/>
                </local-cache>
            </cache-container>
            ….
        </subsystem>

Как мы можем судить по конфигурации, ejb  при пассивации сохраняется в кэше на диске, если вы перейдете в каталог JBOSS_HOME/Standalone/data/infinispan/ejb/ вы увидите файл  кэша где будут сохранятся ваши  пассивируемые ejb  - jboss_ejb_war.war.dat для моего web  приложения.  Еще нужно рассказать об одной аннотации,  это @Remove. Так как наш экземпляр ejb попадает в кэш и кэш наш ограничен максимальным размером (max-size="10000"), отсюда следует, что нужно его чистить от ненужных нам бинов. Чистить можно двумя способами, вручную вызвав метод помеченный аннотацией @Remove или настроив метод вытеснения кэша, по умолчанию он выключен. Для того что бы его включить нужно в конфиге прописать строчку со стратегией вытеснения:

….
<local-cache “passivation" batching="true">
….
                    <eviction strategy="LRU" max-entries="10000"/>
….
</local-cache>
….

Расскажу о некоторых параметрах атрибута strategy:
·         Очередь, первым пришел, первым ушел - FIFO.
·         По максимальному времени не использования объекта кэша, в кэше – LRU.
·         Не используется метод вытеснения, т.е. ручное вытеснение объекта кэша, из кэша – NONE.

И так закрепим наши знания примером, создадим EJB бин и JSP страницу, вызывающую метод этого бина. Создадим Stateful EJB:
package com.vit;

import org.jboss.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.*;

@Stateful(name="BeanStateful")
public class SessionBean1  {
    private static Logger log = Logger.getLogger(SessionBean1.class.getName());
    private String name;

    public SessionBean1() {
        name = "Hello EJB Bean";
    }

    public String getName() {
        return new String(name);
    }

    public void setName(String name) {
        this.name = name;
    }

     @PreDestroy
    public void destroyInit(){
        log.info(String.format("%s\n","================method @PreDestroy call================"));
    }

    @PostConstruct
    public void postConstructInit(){
        log.info(String.format("%s\n","================method @PostConstruct call================"));
    }

    @PostActivate
    public void postActivate_(){
        log.info(String.format("%s\n","================method @PostActivate call================"));
    }

    @PrePassivate
    public void prePassivate_(){
        log.info(String.format("%s\n","================method @PrePassivate call================"));
    }

    @Remove
    public void preRemove(){
        log.info(String.format("%s\n","================method @Remove call================"));
    }
}

И код jsp  страницы:

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page pageEncoding="UTF-8" %>
<%@ page session="false" %>
<%@ page import="com.vit.SessionBean1 " %>
<%@ page import="javax.naming.Context" %>
<%@ page import="javax.naming.InitialContext" %>
<html>
<head>
    <title>Home</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h1>Hello world!</h1>
<%
    Context context = new InitialContext();
    SessionBean1 calc1 = (SessionBean1) context.lookup("java:app/jboss_ejb_war/BeanStateful!com.vit.SessionBean1");
    calc1.setName("Hello Session Stateful Bean!!!");
    out.println(calc1.getName());//вывод установленного методом setName значения"Hello Session Stateful Bean!!!"   
    calc1.preRemove();
%>
</body>
</html>

 Еще раз напоминаю, для того что бы развернуть приложение вы его должны запаковать в war архив и скопировать в каталог JBOSS_HOME/Standalone/deployments.

Комментариев нет:

Отправить комментарий