Primavera – @Transactional – ¿Qué sucede en el fondo?

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

Pero, tengo las siguientes dudas:

  1. Escuché que Spring crea una clase proxy . ¿Alguien puede explicar esto con más profundidad ? ¿Qué reside realmente en esa clase proxy? ¿Qué pasa con la clase real? ¿Y cómo puedo ver la clase proxied creada de Spring?
  2. También leí en Spring Docs que:

Nota: Como este mecanismo se basa en proxies, solo se interceptarán llamadas a métodos ‘externos’ que entren a través del proxy . Esto significa que la “auto invocación”, es decir, un método dentro del objeto objective que llama a otro método del objeto objective, 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é solo las llamadas externas al método estarán bajo Transacción y no los métodos de auto invocación?

Este es un gran tema. El documento de referencia de Spring le dedica varios capítulos. Recomiendo leer los de Progtwigción Orientada a Aspectos y Transacciones , 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 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 misma interfaz (s) 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 observó, el mecanismo proxy solo funciona cuando las llamadas provienen de algún objeto externo. Cuando realiza una llamada interna dentro del objeto, realmente está haciendo una llamada a través de la referencia ” this “, que elude al proxy. Sin embargo, hay formas de solucionar este problema. Explico un enfoque en esta publicación del foro 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 ” yo “. Entonces, si necesito hacer 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 de 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.

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 “objective” (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 objective de frijol. Para los beans objective 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 objective. Cuando finaliza la invocación, TransactionInterceptor confirma / retrotrae la transacción. Es transparente para el código del cliente.

En cuanto a la cuestión del “método externo”, si su bean invoca uno de sus propios métodos, 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?

Como persona visual, me gusta sopesar con un diagtwig de secuencia del patrón proxy. Si no sabe cómo leer las flechas, leo la primera de esta manera: El Client ejecuta Proxy.method() .

  1. El cliente llama a un método en el objective desde su perspectiva, y es interceptado en silencio por el proxy
  2. Si se define un aspecto anterior, el proxy lo ejecutará
  3. Luego, se ejecuta el método real (objective)
  4. After-returning y after-throwing son aspectos opcionales que se ejecutan después de que el método retorna y / o si el método arroja una excepción
  5. Después de eso, el proxy ejecuta el aspecto posterior (si está definido)
  6. Finalmente, el proxy vuelve al cliente que llama

Diagrama de secuencia de patrón de proxy (Se me permitió publicar la foto a condición de que mencionara sus orígenes. Autor: Noel Vaes, sitio web: http://www.noelvaes.eu)

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

Si está utilizando la llamada JPA, entonces todas las confirmaciones se encuentran en 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. Internamente, la transacción JPA es utilizada por Spring.