Où dois-je mettre l’annotation @Transactional: à une définition d’interface ou à une classe d’implémentation?

La question du titre dans le code:

@Transactional (readonly = true) public interface FooService { void doSmth (); } public class FooServiceImpl implements FooService { ... } 

contre

 public interface FooService { void doSmth (); } @Transactional (readonly = true) public class FooServiceImpl implements FooService { ... } 

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

La recommandation de l’équipe Spring est d’annoter uniquement les classes concrètes avec l’annotation @Transactional , par opposition aux interfaces d’annotation. Vous pouvez certainement placer l’annotation @Transactional sur une interface (ou une méthode d’interface), mais cela ne fonctionnera que si vous utilisez des proxys basés sur des interfaces. Le fait que les annotations ne soient pas héritées signifie que si vous utilisez des proxy basés sur des classes, les parameters de transaction ne seront pas reconnus par l’infrastructure de proxy basée sur les classes et que l’object ne sera pas encapsulé dans un proxy transactionnel . Alors, prenez les conseils de l’équipe Spring et @Transactional seulement les classes concrètes (et les méthodes des classes concrètes) avec l’annotation @Transactional .

Remarque: Étant donné que ce mécanisme est basé sur des proxys, seuls les appels de méthodes «externes» provenant du proxy seront interceptés. Cela signifie que «l’auto-invocation», c’est-à-dire une méthode de l’object cible appelant une autre méthode de l’object cible, ne conduira pas à une transaction réelle à l’exécution même si la méthode invoquée est marquée par @Transactional !

(Soulignement ajouté à la première phrase, autre accentuation de l’original.)

Vous pouvez les placer sur l’interface mais attention, les transactions risquent de ne pas se produire dans certains cas. Voir la deuxième astuce dans Secion 10.5.6 des documents de spring:

Spring recommande de n’annoter que des classes concrètes (et des méthodes de classes concrètes) avec l’annotation @Transactional, par opposition aux interfaces d’annotation. Vous pouvez certainement placer l’annotation @Transactional sur une interface (ou une méthode d’interface), mais cela ne fonctionne que comme vous vous y attendez si vous utilisez des proxys basés sur des interfaces. Le fait que les annotations Java ne soient pas héritées des interfaces signifie que si vous utilisez des proxy basés sur des classes (proxy-target-class = “true”) ou l’aspect basé sur le tissage (mode = “aspectj”), les parameters de transaction sont pas reconnu par l’infrastructure de proxy et de tissage, et l’object ne sera pas encapsulé dans un proxy transactionnel, ce qui serait décidément mauvais.

Je recommanderais de les mettre sur la mise en œuvre pour cette raison.

De plus, pour moi, les transactions semblent être un détail d’implémentation pour qu’elles soient dans la classe d’implémentation. Imaginez que vous ayez des implémentations de wrapper pour la journalisation ou les implémentations de test (mocks) qui n’ont pas besoin d’être transactionnelles.

La recommandation de Spring est d’annoter les implémentations concrètes au lieu d’une interface. Il n’est pas incorrect d’utiliser l’annotation sur une interface, il est simplement possible d’en abuser et de contourner par inadvertance votre déclaration @Transaction.

Si vous avez marqué quelque chose de transactionnel dans une interface et que vous vous référez à l’une de ses classes d’implémentation ailleurs au spring, il n’est pas évident que l’object créé par Spring ne respecte pas l’annotation @Transactional.

En pratique, cela ressemble à ceci:

 public class MyClass implements MyInterface { private int x; public void doSomethingNonTx() {} @Transactional public void toSomethingTx() {} } 

Support de @Transactional sur les classes concrètes:

Je préfère concevoir une solution en 3 sections: une API, une implémentation et un Web (si nécessaire). Je fais de mon mieux pour garder l’API aussi légère / simple / POJO que possible en minimisant les dépendances. C’est particulièrement important si vous jouez dans un environnement dissortingbué / intégré où vous devez partager les API.

Mettre @Transactional nécessite des bibliothèques Spring dans la section API, dont IMHO n’est pas efficace. Je préfère donc l’append à l’implémentation où la transaction est en cours d’exécution.

Le placer sur l’interface est une bonne chose tant que tous les implémenteurs prévisibles de votre IFC se soucient des données TX (les transactions ne sont pas des problèmes que seules les bases de données traitent). Si la méthode ne se soucie pas de TX (mais vous devez la mettre pour Hibernate ou autre), mettez-la sur l’impl.

En outre, il serait peut-être préférable de placer @Transactional sur les méthodes de l’interface:

 public interface FooService { @Transactional(readOnly = true) void doSmth(); } 

Veuillez regarder le lien ci-dessous qui illustre le problème avec un exemple simple mais explicatif:

http://kim.saabye-pedersen.org/2013/05/spring-annotation-on-interface-or-class.html