tutorial entre ejemplo diferencias beans bean java servlets java-ee ejb stateful

entre - java ee beans



Uso correcto de beans con Stateful Servlets (5)

Algunos detalles más sobre ConcurrentAccessException : según la especificación EJB, la aplicación sincroniza el acceso a SLSB. servidor. Sin embargo, este no es el caso con SFSB. La carga de asegurarse de que no se acceda al SFSB simultáneamente está en los hombros del desarrollador de la aplicación.

¿Por qué? Bueno, la sincronización de SLSB solo es necesaria en el nivel de instancia. Es decir, cada instancia particular de SLSB está sincronizada, pero puede tener varias instancias en un grupo o en un nodo diferente en un clúster, y las solicitudes simultáneas en instancias diferentes no son un problema. Desafortunadamente, esto no es tan fácil con SFSB debido a la pasivación / activación de instancias y la replicación en todo el clúster. Esta es la razón por la cual la especificación no hace cumplir esto. Eche un vistazo a esta discusión si le interesa el tema.

Esto significa que usar SFSB de servlet es complicado. Un usuario con múltiples ventanas de la misma sesión o recarga de página antes de que finalice la renderización puede generar acceso concurrente. Cada acceso al EJB que se realiza en un servlet necesita teóricamente estar sincronizado en el mismo bean. Lo que hice fue crear un InvocationHandler para sincronizar todas las invocaciones en la instancia particular de EJB:

public class SynchronizationHandler implements InvocationHandler { private Object target; // the EJB public SynchronizationHandler( Object bean ) { target = bean; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { synchronized( target ) { // invoke method to the target EJB } }

}

Luego, justo después de obtener la referencia remota al EJB, lo ajusta con SynchronizationHandler . De esta forma, está seguro de que esta instancia particular no se accederá simultáneamente desde su aplicación (siempre que se ejecute en una sola JVM). También puede escribir una clase contenedora regular que sincronice todos los métodos del bean.

Mi conclusión es sin embargo: use SLSB siempre que sea posible.

EDITAR :

Esta respuesta refleja las especificaciones EJB 3.0 (sección 4.3.13):

Los clientes no pueden hacer llamadas concurrentes a un objeto de sesión con estado. Si un método comercial invocado por el cliente está en progreso en una instancia cuando otra llamada invocada por el cliente, del mismo cliente o diferente, llega a la misma instancia de una clase bean de sesión con estado, si el segundo cliente es un cliente del negocio del bean interfaz, la invocación simultánea puede dar como resultado que el segundo cliente reciba javax.ejb.ConcurrentAccessException

Dichas restricciones se eliminaron en EJB 3.1 (sección 4.3.13):

De forma predeterminada, los clientes pueden hacer llamadas concurrentes a un objeto de sesión con estado y el contenedor es necesario para serializar dichas solicitudes concurrentes.

[...]

El Desarrollador de Bean puede especificar opcionalmente que las solicitudes concurrentes de clientes a un bean de sesión con estado estén prohibidas. Esto se hace utilizando el elemento de descriptor de despliegue anotación @AccessTimeout o access-timeout con un valor de 0. En este caso, si un método comercial invocado por el cliente está en progreso en una instancia cuando otra llamada invocada por el cliente, del mismo o diferente cliente, llega a la misma instancia de un bean de sesión con estado, si el segundo cliente es un cliente de la interfaz de negocio del bean o vista sin interfaz, la invocación simultánea debe dar como resultado que el segundo cliente reciba javax.ejb.ConcurrentAccessException

Actualmente tenemos un bean Stateful que se inyecta en un servlet. El problema es que a veces obtenemos un Caused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1] Caused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1] cuando se ejecuta un método en el bean con estado.

public class NewServlet extends HttpServlet { @EJB private ReportLocal reportBean; protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { String[] parameters = fetchParameters(request); out.write(reportBean.constructReport(parameters)); } finally { out.close(); } } }

En el código anterior, constructReport comprobará si necesita abrir una nueva conexión a la base de datos especificada en el Informe después de la cual se genera un Informe en HTML a partir de una consulta que se genera a partir de los parámetros especificados.

La razón por la que elegimos usar un bean con estado sobre un bean sin estado fue porque necesitamos abrir una conexión de base de datos a una base de datos desconocida y realizar consultas sobre ella. Con un bean sin estado, parece terriblemente ineficiente abrir y cerrar repetidamente las conexiones de la base de datos con cada instancia inyectada del bean.


Esto no es lo que los beans de sesión con estado (SFSB) están destinados a ser utilizados. Están diseñados para mantener el estado de la conversación, y deben estar vinculados a la sesión http del usuario para mantener ese estado, como una alternativa pesada para almacenar el estado en la sesión directamente.

Si desea mantener cosas como conexiones de bases de datos, entonces hay mejores formas de hacerlo.

La mejor opción es usar un grupo de conexiones. Siempre debe usar un grupo de conexiones, y si está ejecutando dentro de un servidor de aplicaciones (que, si está utilizando EJB, entonces lo está), entonces puede usar fácilmente la configuración del origen de datos de su servidor de aplicaciones para crear un grupo de conexiones, y usar eso dentro de su bean de sesión sin estado (SLSB).


Hasta que proporciones algún código y stacktrace, te sugiero que consideres usar un grupo de conexiones . Si por "base de datos desconocida" se entiende una base de datos cuyos parámetros son suministrados por el usuario final y, por lo tanto, no es posible un grupo de conexiones preconfigurado, puede seguir utilizando el concepto de grupo de conexiones en lugar de abrir una nueva conexión cada vez.

Además, theck este hilo .


Los beans de sesión no se pueden usar al mismo tiempo, como skaffman dijo que estaban destinados a manejar el estado correspondiente a la sesión del cliente y típicamente se almacenan en el objeto de sesión por cliente.

Refactorizar para usar un grupo de bases de datos para manejar solicitudes concurrentes a sus recursos es el camino a seguir.

Mientras tanto, si todo lo que necesita es este uso trivial, puede sincronizar la llamada a constructionReport como en:

synchronised (reportBean) { out.write(reportBean.constructReport(parameters)); }

Tenga en cuenta que esto no es una solución si constructReport toma una cantidad significativa de tiempo en relación con su número de clientes.


nunca debe sincronizar acceso a servlet o ejb ya que esta causa solicita cola y si tiene N simultáneamente usuarios, la última esperará por un tiempo prolongado y a menudo obtendrá una respuesta de tiempo de espera. El método Syncronize no está destinado por este motivo.