2009-07-08 20 views
216

Quiero saber qué sucede realmente cuando anota un método con @Transactional? Por supuesto, sé que Spring ajustará ese método en una transacción.Spring - @Transactional - ¿Qué sucede en el fondo?

Pero, tengo las siguientes dudas:

  1. oí que la primavera se crea una clase de proxy ? ¿Alguien puede explicar esto en más profundidad. ¿Qué reside realmente en esa clase proxy? ¿Qué pasa con la clase real? Y ¿cómo puedo ver creado clase proxy de primavera
  2. También leí en documentos fuente que:

Nota: Dado que este mecanismo está basado en proxies, único método 'externo' llamadas entrantes a través el proxy será interceptado. Esto significa que la "auto invocación", es decir, un método dentro del objeto objetivo que llama a otro método del objeto objetivo, no dará lugar a una transacción real en el tiempo de ejecución, incluso si el método invocado está marcado con @Transactional.

Fuente: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

¿Por qué sólo las llamadas a métodos externos estará bajo transacción y no los métodos de auto-Invocación?

+1

La discusión relevante está aquí: http://stackoverflow.com/questions/3120143/where-should-i-put-transactional-annotation-at-an-interface-definition-or-at-an/3120323#3120323 –

Respuesta

168

Este es un gran tema. El documento de referencia de Spring le dedica varios capítulos. Recomiendo leer los que están en Aspect-Oriented Programming y Transactions, ya que el soporte de transacciones declarativas de Spring usa AOP en su base.

Pero en un nivel muy alto, Spring crea proxies para las clases que declaran @Transactional en la clase o en los miembros. El proxy es casi invisible en tiempo de ejecución. Proporciona una forma para que Spring inyecte comportamientos antes, después o alrededor de las llamadas al método en el objeto que se está aproximando. La gestión de transacciones es solo un ejemplo de los comportamientos que pueden engancharse. Las comprobaciones de seguridad son otra. Y también puede proporcionar los suyos para cosas como el registro. Por lo tanto, cuando anota un método con @Transactional, Spring crea dinámicamente un proxy que implementa la (s) misma (s) interfaz (es) que la clase que está anotando. Y cuando los clientes hacen llamadas a su objeto, las llamadas son interceptadas y los comportamientos son inyectados a través del mecanismo proxy.

Las transacciones en EJB funcionan de manera similar, por cierto.

Como observaste, el mecanismo proxy solo funciona cuando las llamadas entran desde algún objeto externo. Cuando realiza una llamada interna dentro del objeto, realmente está realizando una llamada a través de la referencia "this", que elude el proxy. Sin embargo, hay formas de solucionar este problema. Explico un enfoque en this forum post en el que utilizo un BeanFactoryPostProcessor para inyectar una instancia del proxy en clases de "autorreferencia" en el tiempo de ejecución. Guardo esta referencia a una variable miembro llamada "me". Luego, si necesito realizar llamadas internas que requieran un cambio en el estado de la transacción del hilo, dirijo la llamada a través del proxy (por ejemplo, "me.someMethod()".) La publicación del foro explica con más detalle. Tenga en cuenta que el código BeanFactoryPostProcessor sería un poco diferente ahora, ya que se escribió en el marco de tiempo de Spring 1.x. Pero con suerte te da una idea. Tengo una versión actualizada que probablemente podría poner a disposición.

+1

>> El proxy es casi invisible en tiempo de ejecución ¡¡Oh !! Tengo curiosidad por verlos :) Descansa ... tu respuesta fue muy completa. Esta es la segunda vez que me ayudas ... Gracias por toda la ayuda. – peakit

+9

No hay problema. Puede ver el código proxy si avanza con un depurador. Esa es probablemente la forma más fácil. No hay magia; solo son clases dentro de los paquetes de Spring. –

+0

Y si el método que tiene la anotación @Transaction está implementando una interfaz, el resorte utilizará la API proxy dinámica para inyectar la transaccionalización y _no_ usar proxies. Prefiero que mis clases transaalizadas implementen interfaces en cualquier caso. –

139

Cuando Spring carga sus definiciones de bean, y se ha configurado para buscar anotaciones @Transactional, creará estos objetos proxy alrededor de su bean real. Estos objetos proxy son instancias de clases que se generan automáticamente en tiempo de ejecución. El comportamiento predeterminado de estos objetos proxy cuando se invoca un método es invocar el mismo método en el bean "objetivo" (es decir, su bean).

Sin embargo, los proxies también se pueden suministrar con interceptores, y cuando estén presentes, estos interceptores serán invocados por el proxy antes de invocar el método de su objetivo de frijol. Para los beans objetivo anotados con @Transactional, Spring creará un TransactionInterceptor y lo pasará al objeto proxy generado. Por lo tanto, cuando llama al método desde el código del cliente, llama al método en el objeto proxy, que primero invoca al TransactionInterceptor (que comienza una transacción), que a su vez invoca el método en su bean objetivo. Cuando finaliza la invocación, TransactionInterceptor confirma/retrotrae la transacción. Es transparente para el código del cliente.

En cuanto al método "método externo", si su bean invoca uno de sus propios métodos, entonces no lo hará a través del proxy. Recuerda, Spring envuelve tu bean en el proxy, tu bean no lo sabe. Solo las llamadas desde "afuera" de su bean pasan por el proxy.

¿Eso ayuda?

+20

> Recuerde, Spring ajusta su bean en el proxy, su bean no tiene conocimiento de eso ** Esto lo dice todo. Que gran respuesta. Gracias por ayudarnos. ** – peakit

+0

Gran explicación para el proxy y los interceptores. Ahora entiendo que primavera implementar un objeto proxy para interceptar llamadas a un bean objetivo. ¡Gracias! – dharag

+5

¡La respuesta es tan buena que simplemente traté de votarlo para que se me presentara un mensaje de error que ya lo había votado anteriormente! – Mustafa

20

Como persona visual, me gusta pesar con un diagrama de secuencia del patrón de proxy. Si no sabes cómo leer las flechas, leo la primera como esta: Client ejecuta Proxy.method().

  1. el cliente llama a un método en el objetivo de su punto de vista, y es en silencio interceptados por el proxy
  2. Si se define un aspecto antes, el proxy lo ejecutará
  3. Entonces, el método real (objetivo) se ejecuta
  4. Abierto regresar y después de lanzamiento de son aspectos opcionales que se ejecutados después devuelve el método y/o si el método produce una excepción
  5. después de eso, el proxy ejecuta el después de aspecto (si está definida)
  6. Finalmente el proxy devuelve al cliente que llama

Proxy Pattern Sequence Diagram (se me permitió publicar la foto en condiciones que he mencionado sus orígenes. Autor: Noel Vaes, sitio web: www.noelvaes.eu)

0

La respuesta más simple es en el método que declare @Transactional el límite de inicio de la transacción y el límite finaliza cuando se completa el método.

Si está utilizando una llamada JPA, entonces todas las confirmaciones están dentro de este límite de transacción. Digamos que estás guardando entidad1, entidad2 y entidad3. Ahora, al guardar la entidad3, se produce una excepción, ya que enitiy1 y entity2 vienen en la misma transacción, de modo que la entidad1 y la entidad2 se revertirán con la entidad3.

Transacción: (entity1.save, entity2.save, entity3.save). Cualquier excepción dará como resultado la reversión de todas las transacciones JPA con DB. La transacción de JPA interna es utilizada por Spring.

Cuestiones relacionadas