Je veux savoir ce qui se passe réellement lorsque vous annotez une méthode avec @Transactional
? Bien sûr, je sais que Spring encapsulera cette méthode dans une transaction.
Mais, j'ai les doutes suivants:
- J'ai entendu dire que Spring crée une classe proxy ? Quelqu'un peut-il expliquer cela plus en profondeur ? Qu'est-ce qui réside réellement dans cette classe proxy? Qu'arrive-t-il à la classe actuelle? Et comment puis-je voir la classe proxy créée par Spring
- J'ai également lu dans Spring docs que:
Remarque: Puisque ce mécanisme est basé sur des mandataires, seuls les appels de méthode «externes» entrant via le mandataire seront interceptés . Cela signifie que «l'auto-invocation», c'est-à-dire une méthode dans l'objet cible appelant une autre méthode de l'objet cible, ne conduira pas à une transaction réelle au moment de l'exécution même si la méthode invoquée est marquée avec
@Transactional
!
Source: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Pourquoi seuls les appels de méthode externes seront sous Transaction et non les méthodes d'auto-invocation?
Réponses:
C'est un gros sujet. Le document de référence Spring lui consacre plusieurs chapitres. Je recommande de lire celles sur la programmation et les transactions orientées aspect , car le support déclaratif des transactions de Spring utilise AOP à sa fondation.
Mais à un niveau très élevé, Spring crée des proxys pour les classes qui déclarent @Transactional sur la classe elle-même ou sur les membres. Le proxy est principalement invisible au moment de l'exécution. Il permet à Spring d'injecter des comportements avant, après ou autour des appels de méthode dans l'objet mandaté. La gestion des transactions n'est qu'un exemple des comportements pouvant être connectés. Les contrôles de sécurité en sont un autre. Et vous pouvez également fournir le vôtre pour des choses comme la journalisation. Ainsi, lorsque vous annotez une méthode avec @Transactional , Spring crée dynamiquement un proxy qui implémente les mêmes interfaces que la classe que vous annotez. Et lorsque les clients effectuent des appels dans votre objet, les appels sont interceptés et les comportements injectés via le mécanisme de proxy.
Soit dit en passant, les transactions dans EJB fonctionnent de la même manière.
Comme vous l'avez observé, à travers, le mécanisme de proxy ne fonctionne que lorsque les appels proviennent d'un objet externe. Lorsque vous effectuez un appel interne au sein de l'objet, vous effectuez réellement un appel via la référence " this ", qui contourne le proxy. Il existe cependant des moyens de contourner ce problème. J'explique une approche dans ce billet de forum dans laquelle j'utilise un BeanFactoryPostProcessor pour injecter une instance du proxy dans des classes "auto-référencées" lors de l'exécution. J'enregistre cette référence dans une variable membre appelée " moi ". Ensuite, si je dois effectuer des appels internes qui nécessitent une modification de l'état de transaction du thread, je dirige l'appel via le proxy (par exemple, " me.someMethod ()".) Le message du forum explique plus en détail. Notez que le code BeanFactoryPostProcessor serait un peu différent maintenant, car il a été réécrit dans le calendrier Spring 1.x. Mais j'espère qu'il vous donne une idée. J'ai une version mise à jour qui Je pourrais probablement mettre à disposition.
la source
BeanFactoryPostProcessor
. Cependant, il existe (à mon avis) une méthode très similaire décrite dans cette réponse: stackoverflow.com/a/11277899/3667003 ... et d'autres solutions dans tout le thread également.Lorsque Spring charge vos définitions de bean et a été configuré pour rechercher des
@Transactional
annotations, il crée ces objets proxy autour de votre bean réel . Ces objets proxy sont des instances de classes qui sont générées automatiquement au moment de l'exécution. Le comportement par défaut de ces objets proxy lorsqu'une méthode est invoquée consiste simplement à invoquer la même méthode sur le bean "cible" (c'est-à-dire votre bean).Cependant, les mandataires peuvent également être fournis avec des intercepteurs, et lorsqu'ils sont présents, ces intercepteurs seront invoqués par le proxy avant d'appeler la méthode de votre bean cible. Pour les beans cible annotés de
@Transactional
, Spring créera unTransactionInterceptor
et le transmettra à l'objet proxy généré. Ainsi, lorsque vous appelez la méthode à partir du code client, vous appelez la méthode sur l'objet proxy, qui appelle d'abord leTransactionInterceptor
(qui commence une transaction), qui à son tour invoque la méthode sur votre bean cible. Une fois l'invocation terminée, la commandeTransactionInterceptor
valide / annule la transaction. Il est transparent pour le code client.En ce qui concerne la "méthode externe", si votre bean invoque une de ses propres méthodes, il ne le fera pas via le proxy. Rappelez-vous, Spring enveloppe votre bean dans le proxy, votre bean n'en a aucune connaissance. Seuls les appels provenant de "l'extérieur" de votre bean passent par le proxy.
Est ce que ça aide?
la source
En tant que personne visuelle, j'aime peser avec un diagramme de séquence du modèle proxy. Si vous ne savez pas lire les flèches, je lis la première comme ceci:
Client
exécuteProxy.method()
.(J'ai été autorisé à poster la photo à condition d'en mentionner les origines. Auteur: Noel Vaes, site internet: www.noelvaes.eu)
la source
La réponse la plus simple est:
Quelle que soit la méthode, vous déclarez
@Transactional
la limite de début et de fin de la transaction à la fin de la méthode.Si vous utilisez l'appel JPA, tous les validations sont avec dans cette limite de transaction .
Disons que vous enregistrez entité1, entité2 et entité3. Maintenant , tout en économisant entity3 une exception se produit , alors que enitiy1 et entité2 est dans la même transaction afin entity1 et entité2 seront rollback avec entity3.
Transaction:
Toute exception entraînera la restauration de toutes les transactions JPA avec DB. Les transactions JPA internes sont utilisées par Spring.
la source
Il est peut-être tard, mais je suis tombé sur quelque chose qui explique bien votre préoccupation liée au proxy (seuls les appels de méthode «externes» entrant via le proxy seront interceptés).
Par exemple, vous avez une classe qui ressemble à ceci
et vous avez un aspect qui ressemble à ceci:
Lorsque vous l'exécutez comme ceci:
}
Résultats de l'appel de kickOff au-dessus du code donné ci-dessus.
mais quand vous changez votre code en
Vous voyez, la méthode appelle en interne une autre méthode afin qu'elle ne soit pas interceptée et la sortie ressemblerait à ceci:
Vous pouvez contourner cela en faisant cela
Extraits de code extraits de: https://www.intertech.com/Blog/secrets-of-the-spring-aop-proxy/
la source
Toutes les réponses existantes sont correctes, mais je ne pense pas pouvoir donner seulement ce sujet complexe.
Pour une explication complète et pratique, vous voudrez peut-être consulter ce guide Spring @Transactional In-Depth , qui fait de son mieux pour couvrir la gestion des transactions en environ 4000 mots simples, avec de nombreux exemples de code.
la source