martes, 7 de septiembre de 2010

Los proxies en Java, Dynamic Proxies vs CGlib, y su uso desde Spring

Empiezo con este artículo a comentar cosas que normalmente llaman la atención cuando las nombro en clase, son temas que cuando se pronuncian el mundo asiente, pero que sinceramente creo casi todos flojeamos con ellas. En esta línea de artículos pienso hablar de conceptos que muchas veces yo doy por sabidos en los cursos. Así podré referenciar a mi propio blog para explicar aspectos que muchas veces no caben en los temarios, ¡jejeje! (malévolo).

Además este es el primer artículo técnico que escribo, los anteriores (y de los que habrá más) han sido de opinión/valoración.


Los Proxies

Todos los días los programadores Java usamos proxies de manera consciente o inconsciente: por ejemplo, en las llamadas remotas vía RMI, o con los componentes EJB, o con los servicios web vía JAX-RPC, incluso cuando usamos HibernateJPA, o en ocasiones Spring AOP, estamos haciendo uso de clases proxy, estos proxies nos hacen el "trabajo sucio" para que nuestro código no tenga que ocuparse de tales tareas, es decir se encargan de serializar-deserializar objetos, abrir-cerrar transacciones, etc.

Pero, ¿Qué es un Proxy exactamente?

Las clases proxy son como
 los dobles de cine.
Una clase Proxy o Delegada es simplemente una clase que implementa los métodos de otra, como si fuera un doble de cine, que asume responsabilidades en nombre de otra clase. Un proxy permite implementar multitud de patrones de diseño de una aplicación de forma más natural y sencilla. Realmente lo que creamos es un objeto doble de otro objeto en memoria.

Vale,  ¿Cómo se construyen?

Normalmente los entornos de desarrollo nos permiten crear clases nuevas que tengan los mismos métodos que otra dada y realizar la retrollamada automática o callback, por ejemplo, en eclipse esto se consigue con el menú Source/Generate Delegate Methods de la perspectiva Java.

Veamos un ejemplo:


Creo que el código anterior no necesita explicación ninguna...

¿Y no se puede hacer mejor?

Sí, ciertamente crear el código fuente de la clase del Proxy "a mano" con o sin ayuda de un IDE es un poco molesto y poco productivo, aunque precisamente eso era lo que hacíamos cuando usábamos herramientas  como el compilador rmic de java hasta la versión 1.4 o al desplegar un módulo ejb-jar 2.x.

Existen dos alternativas para no tener que hacer este trabajo por adelantado en nuestro código fuente: la clases para crear Proxies Dinámicos del paquete Reflection (java.lang.reflect) y la librería para generación de código CGlib:


Dynamic Proxies

A partir de JSE 1.3 incluido en el API de Reflection, Java trae la funcionalidad de crear Dynamic Proxies, es decir clases que se generan dinámicamente para suplantar/modificar/ampliar el comportamiento de otras, veamos el código:


Aquí si tenemos cosas que comentar:

1) Para crear un doble (un proxy dinámico) sólo necesitamos llamar a la función Proxy.newProxyInstance, esta función recibe 3 parámetros:
  • el cargador de clases de la clase de la que queremos hacer el proxy.
  • un array con la interfaz o interfaces que contienen los métodos que queremos interceptar de la clase actor.
  • el objeto que recibirá la retrollamada por parte del proxy, en nuestro caso el doble.

¡Et voilà! automáticamente se invocará la función InvocationHandler.invoke de nuestro objeto doble con las llamadas a las funciones del las interfaces introducidas como segundo parámetro de función newProxyInstance.

Esto permite poder construir clases proxies de cualquier clase que implemente al menos una interfaz. pero ¿y si nuestra clase actor no implementará ninguna interfaz...? entonces tendremos que recurrir a una librería llamada cglib.


CGLib

Este framework realmente es una librería de macros de ASM, que es una librería de manipulación de "bytecode", es decir, de código máquina java. Dentro de la CGLib se pueden encontrar (aunque muy mal documentadas) diversas funciones de utilidad, en nuestro caso vamos a usar una clase llamada net.sf.cglib.proxy.Enhancer 

Veamos el código:


Inspeccionando el código, descubrimos que no hace falta ninguna interfaz para usar la clase Enhancer sólo la programamos para funcionar con los métodos setSuperclass setCallback. Bastante fácil, ¿no?, no es de extrañar que Hibernate e iBatis estén escritos con esta librería de proxies. ¿Cual es mejor? unos hablan del rendimiento algo más lento de los proxies dinámicos, otros hablan de las dependencías con librerías (jars) que impone la CGLib. 

Para mi la diferencia entre ambas es algo más sutil, con los proxies dinámicos el proxy se crea partiendo de una instancia de una clase, con la CGlib el proxy se crea a partir de una clase no de una instancia, de forma que para crear un proxy de un objeto concreto con la cglib hay que copiar los valores de los atributos del objeto molde después de crear el proxy, esto suena a Commons BeanUtils, una de las dependencias de Hibernate...


Spring ProxyFactoryBean

Para acabar este "ladrillo" diré que si usamos Springframework, la creación de proxies se ha automatizado con una clase llamada org.springframework.aop.framework.ProxyFactoryBean que permite crear e inyectar dependencias a nuestro código de objetos que sean proxies creados tanto  con el api de reflection  como con la cglib controlando el propiedad proxyTargetClass de dicha clase, aunque en las últimas versiones de Spring la propia existencia o no de una interfaz a la hora de crear el proxy es lo que determina por defecto el comportamiento de esta clase.

Veamos el ejemplo como colofón:


Espero haber aclarado algo a alguien a estas alturas del post sobre el fantástico mundo de los proxies en Java.

¡Hasta la próxima!


lunes, 26 de julio de 2010

En busca del Grial

La búsqueda

Fue en el mes de febrero pasado cuando descubrí Grails en el Spring 2GX Day, desde entonces he estado trasteando con este framework para desarrollo rápido de aplicaciones web. Yo algo sabía ya de Groovy desde hace un par de años, pero en estos meses me he empapado casi todos los libros de Groovy/Grails que he encontrado (alguno me falta todavía) y además como el que no quiere la cosa, he vuelto a programar "por gusto", cosa que no me ocurria desde que aprendí Spring, y es que ya no programo largo y tendido sino tengo alumnos atendiendo, o como dicen "si no tengo el taxímetro puesto"...

Desarrollo Rápido de Aplicaciones significa que con un numero reducido (reducidísimo) de líneas de código tenemos una gran parte de la funcionalidad de nuestra aplicación desarrollada, puesto que Grails estereotipa la programación de un proyecto web, generalizando los diversos patrones y estrategias de uso común  (MVC, comandos, servicios, DI, plantillas, testing, etc) en una arquitectura en N capas (presentación, negocio, dominio y persistencia)

Los calvarios

Al principio, fui bastante reticente, por dos motivos fundamentalmente:
  1. Que el paradigma "Convention over Configuration" me parece peligroso. Peligroso para la gente que aprenda directamente Grails y que no haya trabajado jamás con una aplicación hecha con Spring e Hibernate (los pilares que mueven este framework) y que puede no llegar a entender que pasa tras toda la tramoya generada. Ya que al final, uno termina teniendo que poner algo que no esta implementado por Grails o cambiar algo para cumplir con las especificaciones y si carece del conocimiento de los distintos patrones idiomaticos para trabajar con Spring, Hibernate, etc, pues termina haciendo "código churro".
  2. Porque había leido varias cosas sobre la penalización del rendimiento que imponen los lenguajes dinamicos y en especial Groovy, pero es cierto, como el propio Graeme Rocher expresó en el SpringGX2Day, que siempre será más barato el hardware que el desarrollo de aplicaciones.
Los dones

he puesto las pegas, ahora vienen las bondades:
  1. Como siempre digo a mis alumnos "Convention over Configuration", significa que una vez que has aprendido algo y lo has hecho una vez, el resto de las veces que vuelves a hacerlo, sólo puede pasar que te equivoques o se te olvide algo. Aparte del cierto regusto que da hacer las cosas manualmente una vez tras otra al principio (hasta que ya se vuelve en hastío), lo único que podemos aportar en un proceso que ya esta bien definido, es el factor humano o mejor dicho "el meter la pata". Por tanto, este paradigma es un arma de doble filo (bueno/malo), como los cuchillos de cocinero que no son aptos para pelar un diente de ajo, pero si para hacer un corte en juliana en segundos.
  2. Existen una gran multitud de aplicaciones donde Grails refulge: como son las de Backoffice para administrar/configurar/monitorizar desde un Frontend web a un sistema en tiempo real escrito en C++ (donde no importe demasiado el rendimiento porque son utilizadas por un reducido número de usuarios concurrentes), o si nos orientamos más en el mundo PYME, como las que tiene la web de taller de coches o un restaurante (aunque nos pese no tienen cientos de miles de hits a la hora), o en el desarrollo de aplicaciones Intranet/Extranet para corporaciones y sus parners.
Las pertrechos
en este tiempo he evaluado SpringToolsSuite, Netbeans e Intellij como corazas para mi lucha. a riesgo se ser partidista, me quedo con él primero. Ciegamente por ser un Eclipse vitaminado (y Eclipse si que es el grial de los IDES) y porque la nueva perspectiva Grails me gusta mucho, espero que en los próximas meses mejore aún más...

    Los templarios y las porfias

    Tras estos meses, entiendo mucho mejor a la caballeros que han encontrado el Grial y que defienden su custodia. A escala internacional, el interés estratégico de Spring con Grails, con el fichaje de Graeme Rocher, la inversión en herramientas (el propio STS) y a nivel nacional, he de reconocer que me dejan pasmado la visión comercial y el esfuerzo por difundir esta tecnología de Nacho Brito y Álvaro Sánchez con  Escuela De Groovy , y que admiro todo el trabajo invertido por Dani LatorreMartín Pérez y Jordi Monné con Jobsket, un desarrollo de los que no parecen hechos por gente de aquí...


    ¿La búsqueda ha terminado?

    Grails. The search is over...¡Not yet for myself!

    No. definitivamente no. Grails esta bien para unos escenarios, pero no para todos. No valorar el perfil tecnológico del equipo de desarrollo, el mantenimiento posterior de la aplicación, los requerimientos de rendimiento y carga puede ser temerario. No caigamos en el antipatron del martillo de oro: para un martillo todo son clavos. Otras herramientas como Spring Roo, Jboss Seam, Jruby on Rails y Scala-Lift parecen prometer el mismo nivel de rapidez y simplicidad que Groovy-Grails. Espero poder hacer caso a Jose Ramón Díaz  y a mi buen amigo Israel Álcazar, para darle vidilla al blog contando por lo menos mis impresiones sobre estos temas y otros que crea que os puedan interesar.



    lunes, 11 de enero de 2010

    Propósitos 2010

    Espero estar aún a tiempo para recoger el testigo lanzado por David Bonilla desde su blog y exponer mis objetivos para este recién estrenado año. Aquí van:

    1. Crear un blog para mí y la empresa. Este propósito es muy concreto se materializa en esta entrada y en las sucesivas.
    2. Contribuir con la Comunidad Java de forma activa. Ha llegado el momento de pasar de sólo recibir a aportar mi pequeño granito en algunos temas. Aún esta por definir (video tutoriales, charlas, etc.), pero este año quiero empezar a contar cosas no sólo desde las clases.
    3. Mejorar mi nivel de inglés. Llevo un año poniéndome las pilas pero aún me queda.
    4. Empezar a dar clases en el extranjero en inglés. Aunque sea sólo un par de cursos de java este año.
    5. Certificarme en java.  Increíble que a estas alturas aún este con estos pelos.(Ya soy SCJP. Actualizado 24/02/2010)
    6. Organizarnos mejor en Pronoide. Olvidar mi antiguo calendario de chinchetas de colores, compartir documentos y código entre la gente de Pronoide, aprovechando las cuentas de Google que hemos comprado.
    7. Aprender más. Todavía mis amigos no técnicos se sorprenden cuando tengo que estudiar Java a estas alturas para dar un curso...pero el día que pare, se acabó...
    8. Ser ecológico. Creo que necesito un eBook (se aceptan sugerencias...) para leer manuales de referencia y pdf's sin gastar tanto papel, ni ocupar tanto...
    9. Transferir responsabilidades a la gente de Pronoide. El eterno reto: delegar, delegar, delegar...
    10. Disponer de más tiempo para mí, para mi mujer y para mi hijo que esta a punto de nacer. Este es el propósito más fundamental.