... sobre el front controller(2003-08-14 08:55:15.0)PermalinkComentarios [8] Akuma ha hecho un curso sobre J2EE, y aunque no quedó del todo satisfecho, como resultado se ha puesto a jugar con el patrón front controller para aplicaciones web (El patrón front controller).
Le comenté el tema de no instanciar una acción para cada petición, y aunque reconoció no entenderlo del todo, lo implementó (Revisado: el patrón front controller). De aquí mi tirón de orejas por creerse las cosas a la ligera, aunque vengan de alguién tan convincente como yo ;-).
Ya que la explicación es un poco larga, pues le robo el post :-).
Antes de nada, supongo que habría claro por qué no queremos andar crendo instancias por cada petición. Bueno, pues no queremos porque andar creando esas instancias es una labor costosa (además por reflection), una labor que si bien ahora mismo podemos considerar requiere un tiempo despreciable es un tiempo que nos podemos ahorrar. Tened en cuenta que en una web más o menos grande (por ejemplo javaHispano, con entre 50 y 100 usuarios concurentes normalmente) podemos estar generando un montón de acciones.
Un entorno web es un entorno concurrente por definición, solucionado en Java en base a hilos, hasta aquí sin problemas. Entonces ¿por qué podemos permitirnos mantener una única instancia de una acción para servir todas las peticiones?. Bien, pues podemos, si y solo sí, solo accedemos a valores propios del hilo, en este caso, valores de la request, valores de la sesión y variables definidas en los métodos. Que la request y la sessión son propias de cada petición esta claro, sobre los métodos quizás no.
Las variables definidas en un método solo viven dentro de ese método, se crean con el método y se destruyen con el método. Es por eso que, mientras nuestras acciones solo utilizen para escritura (para lectura peuden usar variables de instancia) variables de ese tipo, no tendremos problema alguno de concurrencia, cada hilo tendrá las suyas propias.
¿Cual es el problema de esta aproximación?. Que puede invitar al programador (al menos si consigues hacer un framework de éxito) a olvidarse de posibles problemas de concurrencia y que acabe metiendo la pata. ¿Cuando puede ocurrir esto?: cuando te sales del método de ejecución para tratar algunas variables de instancia (datos cacheados y datos de configuración de la acción principalmente, aunque no únicamente), donde si que tendrás que usar la sincronización si piensas cambiar dichos valores.
En todo caso, aún no penseis que la implementación de Akuma es perfecta, más información la encontrareis como comentarios en su post.
URL de la referencia: http://weblogs.javahispano.org/al/entry/sobre_el_front_controller
Comentarios:
A mi el sistema de caché me plantea algunas dudas sobre hasta donde llegar....<br><br>
Supongamos que la <b><i>AccionBean</i></b> recibe de un formulario (por ejemplo una clase Form inicializada a partir del request) un codigo de provincia, y recupera de la base de datos todos los municipios de esa provincia. <br>
Estos municipios se guardan en una colección del ActionBean, y son recuperados con posterioridad por la vista (donde se incluyen en un select html, u listbox)<br>
<b>¿Qu&ecaute; sucede si inmediatamente despues llega otro usuario, y en su request se pide la misma provincia?</b><br>
El sistema de cache que implementa Akuma evitaría construir el objeto, pero no lanzar nuevamente la consulta contra la base de datos.<br>
Por supuesto, se pueden tomar medidas. Una nueva caché de Acciones a partir de las propiedades del objeto Form, guardarlo en la sesión...etc<br><br>
Esto me lleva a un tema que tratare en mi proximo post...(cuando tenga tiempo, que acabo de llegar de vacaciones!!!!)<br>
No me gusta como Structs trata los datos introducidos por los usuarios en los formularios. Hay que crearse una clase que herede de Form, y si tenemos tropecientos AccionBean que toman sus entradas de tropecientos formularios, hay que crearse tropecientas clases FormBean.<br>
En el post describire la solución que adopté en el curro: Forms con propiedades dinamicas a partir de XML, capaces de autovalidarse y de chechear reglas.<br>
Enviado por
pacopaco
en agosto 14, 2003 a las 11:28 PM CEST
#
Paco, en el ejemplo que estas dando estas precisametne saliéndote de lo que yo he coemtnado, al cachear información. La solución es relativamente sencilla, y sería sincronizar el acceso a esa Collection con las provincias.
Ojo, que estoy hablando de sincronizar solo su recuperación (que provocará la carga si no se ha producido ya), pero reduciendo esa sincronización al máximo para no hacer que algunos hilos tenga que esperar más del tiempo necesario.
Sobre el problema de la implemetnación de Akuma, es cierto, la acción se crearía dos veces (pense que lo había escrito, pero como perdí el primer post quizás lo olvidé luego), pero en su caso estamos hablando de clases de ejecución y no tanto de cachear datos, que es a donde va dirigido tu post.
Enviado por
Al
en agosto 15, 2003 a las 10:07 AM CEST
#
Hola Al!,<br>
Antes de nada mi nombre es Alvaro (el nick lleva a confusión ;)<br>
Creo que no me expliqué bien, o no entiendo tu contestacion.<br>
El problema es que tenemos un Accion, y ese mismo se ocupa de devolver los resultados de su ejecucion, algo así:
<i>public void ejecutate()</i><br>
<i>public Object[] getResultados()</i><br>
Los resultados son almacenados internamente en una colección, y se devuelven cuando se piden.<br>
Con la aproximación basada en una sola instancia por Accion, una vez ejecutada y accedidos sus resultados, habrá que resetear su estado (poner la coleccion a null, p.ej.). Si a lo largo de N dias M usuarios piden lo mismo, estamos haciendo N*M consultas que nos podriamos haber ahorrado con una aproximacion diferente. No digo que haya que crear cada vez un objeto, sino buscar alguna forma inteligente de instanciarlos <br>(por ejemplo, sobreescribir el hashCode y el equals del objeto Form que representa un formulario Http, de forma que el hashCode() sea siempre el mismo siempre que los parametros del Form (clases que representen los <input type/> html) sean los mismos, en nuestro caso el codigo de provincia.<br>
De esta forma creariamos un Accion cada vez, siempre y cuando en nuestra cache no haya ninguna entrada para el Form de la peticion.<br>
Enviado por
pacopaco
en agosto 15, 2003 a las 10:34 AM CEST
#
Replicandome amemesmo ;0)<br>
Si nos ponemos puristas, mejor crear una clase <b>ActionResult</b> que almacene los resultados de una Accion, y cachear estos y no las acciones. Asi, antes de crear y ejecutar una Accion, miramos si existe una entrada en la cache para el Form que representa el formulario Html.
Enviado por
pacopaco
en agosto 15, 2003 a las 10:44 AM CEST
#
Álvaro... el problema esta en saebr que cosas puedes cachear y como. El planteamineto de akuma (y el que yo cometanba) iba dirigido a evitar la instanciación innecesria de clases, aunque indicaba que en el caso de querer cachear datos (que es lo que tu quieres hacer!), hay que prestar más atención, sobre que cachear y donde almacenar esa información.
Bien, estoy de acuerdo contigo en el tema de tener que refinar el tema de cachear los objetos, pero es que el tema de la cache es un tema complejo, hay que saber que cachear y que no.
Por ejemplo, puedes cachear las diez últimas entradas en un foro, pues son las más probables de utilizar repetidamente, pero no deberías cachear los resultados de búsquedas libres (indicando el texto a buscar, por ejemplo), pues esas varían tanto que es poco probable que coincidan dos.
Pero que pasa si tu queires cachear los resultados de la búsqueda de un usuario para luego trabajar sobre ellos, paginarlos, etc. Pues entonces deberías hacerlo, pero donde?, obviamente en la acción no, si no que tendrás que hacerlo en la parte privada de un usuario, digamos la sesión.
Lo que tu haces (si esos dos métodos son la interface real que tienes), almacenando los resultado dentro de un atributo la acción hace simplemente imposible (de forma sencilla) mantener una única instancia de las acciones, simplemetne podrás reutilizarlas, es decir, tener una pool de objetos, no una cache.
Nos vamos entendiendo ahora?. Debemos hacerlo en algún otro sitio?.
Enviado por
Al
en agosto 15, 2003 a las 02:06 PM CEST
#
<b>[AL]</b> <i>De aquí mi tirón de orejas por creerse las cosas a la ligera, aunque vengan de alguién tan convincente como yo ;-).</i> Cierto no debi creerte sin mas, y menos a alguien como tu :-P
* <i>Sobre el problema de la implemetnación de Akuma, es cierto, la acción se crearía dos veces (pense que lo había escrito, pero como perdí el primer post quizás lo olvidé luego), pero en su caso estamos hablando de clases de ejecución y no tanto de cachear datos, que es a donde va dirigido tu post</i> Esto no me queda muy claro a que te refieres, la accion se instancia una unica vez y se almacena en la hashtable, el resto de las ocasiones se devuelve la instancia almacenada.
* <i>La concurrencia</i> No te creas que lo tengo del todo claro, es cierto que cuando un hilo ejecuta un metodo las variables locales pertenecen a cada hilo, pero en este caso lo que me dejo cierta duda era que accedian a un metodo estático getAccion y a un atributo de la clase que tambien era estatico. De todas formas he cambiado la implementacion del AccionFactoy (ahora sigue el patron Singleton), ahora no se accede a nada estatico.
<b>[Alvaro]</b> Es cierto que para N forms iguales se ejecutaria N veces la misma accion/consulta con la consiguiente sobrecarga. Segun comentas creo que propones que creando objetos Form que representen los formularios y cacheando los estos y el resultado que produjeron (ActionResult x ejemp) evitariamos realizar N veces la misma acion/consulta. ¿Es eso?. Esto me crea una duda. ¿No estariamos creando un cacheado demasiado grande?. Y se es asi, ¿seria un pool de objetos una buena solucion?.
Por otra parte comentar que mi intencion era crear un ejemplo lo mas sencillo posible (dados mis conocimientos claro, no podia hacer uno mejor) aunque los post estan siendo muy constructivos.
PD Como soy muy pesado dentro de un par de dias volvere al ataque con "el patron front controller 2ª parte", en la que quiero implementar un par de cosillas mas...
<ul>
<li> Control de eventos </li>
<li> redirecionamiento (forward,sendRedirect) </li>
<li> AccionForms,ya se que es muy pesado una accionForm por cada formulario, pero no se me ocurre otra forma</li>
<li> y ahora me esa entrando la curiosidad del cacheado de datos</li>
</ul>
Sugerencias...
Enviado por
Unknown
en agosto 15, 2003 a las 02:26 PM CEST
#
upss el anterior era yo...AHHH Al te me has colado mientras lo escribia... ahora si que me he quedado perdido con el cacheado.
Enviado por
Akuma
en agosto 15, 2003 a las 02:30 PM CEST
#
Akuma... ummm... eso de que se crearían dos instancias de una misma acción era en el supuesto que comento Álvaro de la llegada en el mismo momento de dos peticiones.
Y sobre la concurrencia. Bueno, yo hablo de la ejecución de las acciones (que no es en base a métiodos estáticos), no de obtener las acciones a ejecutar. En realidad, el problema de las dos acciones creadas te pasa por no haber controlado la concurrencia en ese momento.
Otra solución a esto último sería la instanaciación de las acciones en tiempo de carga de la aplicación, y no bajo petición como lo tienes ahora.
Sobre todo lo que quieres... vamos a tener mucho que de hablar en los próximos meses me parece a mí ;-).
Enviado por
Al
en agosto 15, 2003 a las 02:36 PM CEST
#
A mi el sistema de caché me plantea algunas dudas sobre hasta donde llegar....<br><br>
Supongamos que la <b><i>AccionBean</i></b> recibe de un formulario (por ejemplo una clase Form inicializada a partir del request) un codigo de provincia, y recupera de la base de datos todos los municipios de esa provincia. <br>
Estos municipios se guardan en una colección del ActionBean, y son recuperados con posterioridad por la vista (donde se incluyen en un select html, u listbox)<br>
<b>¿Qu&ecaute; sucede si inmediatamente despues llega otro usuario, y en su request se pide la misma provincia?</b><br>
El sistema de cache que implementa Akuma evitaría construir el objeto, pero no lanzar nuevamente la consulta contra la base de datos.<br>
Por supuesto, se pueden tomar medidas. Una nueva caché de Acciones a partir de las propiedades del objeto Form, guardarlo en la sesión...etc<br><br>
Esto me lleva a un tema que tratare en mi proximo post...(cuando tenga tiempo, que acabo de llegar de vacaciones!!!!)<br>
No me gusta como Structs trata los datos introducidos por los usuarios en los formularios. Hay que crearse una clase que herede de Form, y si tenemos tropecientos AccionBean que toman sus entradas de tropecientos formularios, hay que crearse tropecientas clases FormBean.<br>
En el post describire la solución que adopté en el curro: Forms con propiedades dinamicas a partir de XML, capaces de autovalidarse y de chechear reglas.<br>
Enviado por pacopaco en agosto 14, 2003 a las 11:28 PM CEST #
Paco, en el ejemplo que estas dando estas precisametne saliéndote de lo que yo he coemtnado, al cachear información. La solución es relativamente sencilla, y sería sincronizar el acceso a esa Collection con las provincias.
Ojo, que estoy hablando de sincronizar solo su recuperación (que provocará la carga si no se ha producido ya), pero reduciendo esa sincronización al máximo para no hacer que algunos hilos tenga que esperar más del tiempo necesario.
Sobre el problema de la implemetnación de Akuma, es cierto, la acción se crearía dos veces (pense que lo había escrito, pero como perdí el primer post quizás lo olvidé luego), pero en su caso estamos hablando de clases de ejecución y no tanto de cachear datos, que es a donde va dirigido tu post.
Enviado por Al en agosto 15, 2003 a las 10:07 AM CEST #
Hola Al!,<br>
Antes de nada mi nombre es Alvaro (el nick lleva a confusión ;)<br>
Creo que no me expliqué bien, o no entiendo tu contestacion.<br>
El problema es que tenemos un Accion, y ese mismo se ocupa de devolver los resultados de su ejecucion, algo así:
<i>public void ejecutate()</i><br>
<i>public Object[] getResultados()</i><br>
Los resultados son almacenados internamente en una colección, y se devuelven cuando se piden.<br>
Con la aproximación basada en una sola instancia por Accion, una vez ejecutada y accedidos sus resultados, habrá que resetear su estado (poner la coleccion a null, p.ej.). Si a lo largo de N dias M usuarios piden lo mismo, estamos haciendo N*M consultas que nos podriamos haber ahorrado con una aproximacion diferente. No digo que haya que crear cada vez un objeto, sino buscar alguna forma inteligente de instanciarlos <br>(por ejemplo, sobreescribir el hashCode y el equals del objeto Form que representa un formulario Http, de forma que el hashCode() sea siempre el mismo siempre que los parametros del Form (clases que representen los <input type/> html) sean los mismos, en nuestro caso el codigo de provincia.<br>
De esta forma creariamos un Accion cada vez, siempre y cuando en nuestra cache no haya ninguna entrada para el Form de la peticion.<br>
Enviado por pacopaco en agosto 15, 2003 a las 10:34 AM CEST #
Replicandome amemesmo ;0)<br>
Si nos ponemos puristas, mejor crear una clase <b>ActionResult</b> que almacene los resultados de una Accion, y cachear estos y no las acciones. Asi, antes de crear y ejecutar una Accion, miramos si existe una entrada en la cache para el Form que representa el formulario Html.
Enviado por pacopaco en agosto 15, 2003 a las 10:44 AM CEST #
Álvaro... el problema esta en saebr que cosas puedes cachear y como. El planteamineto de akuma (y el que yo cometanba) iba dirigido a evitar la instanciación innecesria de clases, aunque indicaba que en el caso de querer cachear datos (que es lo que tu quieres hacer!), hay que prestar más atención, sobre que cachear y donde almacenar esa información.
Bien, estoy de acuerdo contigo en el tema de tener que refinar el tema de cachear los objetos, pero es que el tema de la cache es un tema complejo, hay que saber que cachear y que no.
Por ejemplo, puedes cachear las diez últimas entradas en un foro, pues son las más probables de utilizar repetidamente, pero no deberías cachear los resultados de búsquedas libres (indicando el texto a buscar, por ejemplo), pues esas varían tanto que es poco probable que coincidan dos.
Pero que pasa si tu queires cachear los resultados de la búsqueda de un usuario para luego trabajar sobre ellos, paginarlos, etc. Pues entonces deberías hacerlo, pero donde?, obviamente en la acción no, si no que tendrás que hacerlo en la parte privada de un usuario, digamos la sesión.
Lo que tu haces (si esos dos métodos son la interface real que tienes), almacenando los resultado dentro de un atributo la acción hace simplemente imposible (de forma sencilla) mantener una única instancia de las acciones, simplemetne podrás reutilizarlas, es decir, tener una pool de objetos, no una cache.
Nos vamos entendiendo ahora?. Debemos hacerlo en algún otro sitio?.
Enviado por Al en agosto 15, 2003 a las 02:06 PM CEST #
<b>[AL]</b> <i>De aquí mi tirón de orejas por creerse las cosas a la ligera, aunque vengan de alguién tan convincente como yo ;-).</i> Cierto no debi creerte sin mas, y menos a alguien como tu :-P
* <i>Sobre el problema de la implemetnación de Akuma, es cierto, la acción se crearía dos veces (pense que lo había escrito, pero como perdí el primer post quizás lo olvidé luego), pero en su caso estamos hablando de clases de ejecución y no tanto de cachear datos, que es a donde va dirigido tu post</i> Esto no me queda muy claro a que te refieres, la accion se instancia una unica vez y se almacena en la hashtable, el resto de las ocasiones se devuelve la instancia almacenada.
* <i>La concurrencia</i> No te creas que lo tengo del todo claro, es cierto que cuando un hilo ejecuta un metodo las variables locales pertenecen a cada hilo, pero en este caso lo que me dejo cierta duda era que accedian a un metodo estático getAccion y a un atributo de la clase que tambien era estatico. De todas formas he cambiado la implementacion del AccionFactoy (ahora sigue el patron Singleton), ahora no se accede a nada estatico.
<b>[Alvaro]</b> Es cierto que para N forms iguales se ejecutaria N veces la misma accion/consulta con la consiguiente sobrecarga. Segun comentas creo que propones que creando objetos Form que representen los formularios y cacheando los estos y el resultado que produjeron (ActionResult x ejemp) evitariamos realizar N veces la misma acion/consulta. ¿Es eso?. Esto me crea una duda. ¿No estariamos creando un cacheado demasiado grande?. Y se es asi, ¿seria un pool de objetos una buena solucion?.
Por otra parte comentar que mi intencion era crear un ejemplo lo mas sencillo posible (dados mis conocimientos claro, no podia hacer uno mejor) aunque los post estan siendo muy constructivos.
PD Como soy muy pesado dentro de un par de dias volvere al ataque con "el patron front controller 2ª parte", en la que quiero implementar un par de cosillas mas...
<ul>
<li> Control de eventos </li>
<li> redirecionamiento (forward,sendRedirect) </li>
<li> AccionForms,ya se que es muy pesado una accionForm por cada formulario, pero no se me ocurre otra forma</li>
<li> y ahora me esa entrando la curiosidad del cacheado de datos</li>
</ul>
Sugerencias...
Enviado por Unknown en agosto 15, 2003 a las 02:26 PM CEST #
upss el anterior era yo...AHHH Al te me has colado mientras lo escribia... ahora si que me he quedado perdido con el cacheado.
Enviado por Akuma en agosto 15, 2003 a las 02:30 PM CEST #
Akuma... ummm... eso de que se crearían dos instancias de una misma acción era en el supuesto que comento Álvaro de la llegada en el mismo momento de dos peticiones.
Y sobre la concurrencia. Bueno, yo hablo de la ejecución de las acciones (que no es en base a métiodos estáticos), no de obtener las acciones a ejecutar. En realidad, el problema de las dos acciones creadas te pasa por no haber controlado la concurrencia en ese momento.
Otra solución a esto último sería la instanaciación de las acciones en tiempo de carga de la aplicación, y no bajo petición como lo tienes ahora.
Sobre todo lo que quieres... vamos a tener mucho que de hablar en los próximos meses me parece a mí ;-).
Enviado por Al en agosto 15, 2003 a las 02:36 PM CEST #