Onde devo colocar anotação @Transactional: em uma definição de interface ou em uma class de implementação?

A questão do título no código:

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

vs

 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

A recomendação da equipe do Spring é que você só anote classs concretas com a anotação @Transactional , ao contrário de anotar as interfaces. Você certamente pode colocar a anotação @Transactional em uma interface (ou um método de interface), mas isso só funcionará como você esperaria se estivesse usando proxies baseados em interface. O fato de as annotations não serem herdadas significa que, se você estiver usando proxies baseados em class, as configurações de transação não serão reconhecidas pela infraestrutura de proxy baseada em class e o object não será empacotado em um proxy transacional (o que seria decididamente ruim ) . Então, por favor, siga o conselho da equipe do Spring e anote apenas as classs concretas (e os methods das classs concretas) com a anotação @Transactional .

Nota: Como esse mecanismo é baseado em proxies, somente chamadas de método ‘externas’ que entram através do proxy serão interceptadas. Isso significa que ‘auto-invocação’, ou seja, um método dentro do object de destino que chama algum outro método do object de destino, não levará a uma transação real em tempo de execução, mesmo se o método invocado estiver marcado com @Transactional !

(Ênfase adicionada à primeira frase, outra ênfase do original.)

Você pode colocá-los na interface, mas avise que as transactions podem não acontecer em alguns casos. Veja a segunda dica em Secion 10.5.6 da spring docs:

O Spring recomenda que você só anote classs concretas (e methods de classs concretas) com a anotação @Transactional, ao contrário de anotar as interfaces. Você certamente pode colocar a anotação @Transactional em uma interface (ou um método de interface), mas isso funciona apenas como você esperaria se estivesse usando proxies baseados em interface. O fato de que as annotations Java não são herdadas de interfaces significa que, se você estiver usando proxies baseados em class (proxy-alvo-class = “true”) ou o aspecto baseado em tecelagem (mode = “aspectj”), as configurações da transação não é reconhecido pela infra-estrutura de proxy e tecelagem, e o object não será envolvido em um proxy transacional, o que seria decididamente ruim.

Eu recomendaria colocá-los na implementação por esse motivo.

Além disso, para mim, as transactions parecem ser um detalhe de implementação, portanto, elas devem estar na class de implementação. Imagine ter implementações de wrapper para log ou implementações de teste (mocks) que não precisem ser transacionais.

A recomendação de Spring é que você anote as implementações concretas em vez de uma interface. Não é incorreto usar a anotação em uma interface, só é possível usar esse recurso de maneira inadequada e ignorar inadvertidamente sua declaração @Transaction.

Se você marcou algo transacional em uma interface e, em seguida, faz referência a uma de suas classs de implementação em outro lugar na primavera, não é muito óbvio que o object que a fonte cria não respeitará a anotação @Transactional.

Na prática, parece algo assim:

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

Apoiando @Transactional nas classs concretas:

Eu prefiro arquitetar uma solução em 3 seções em geral: uma API, uma implementação e uma Web (se necessário). Eu tento o meu melhor para manter a API como leve / simples / POJO possível minimizando as dependencies. É especialmente importante se você jogar em um ambiente distribuído / integrado, onde você tem que compartilhar muito as APIs.

Colocar @Transactional requer bibliotecas Spring na seção da API, o que IMHO não é eficaz. Então eu prefiro adicioná-lo na implementação onde a transação está sendo executada.

Colocá-lo na interface é bom, desde que todos os implementadores previsíveis do seu IFC se importem com os dados do TX (transactions não são problemas que apenas bancos de dados lidam). Se o método não se importar com TX (mas você precisa colocá-lo lá para o Hibernate ou qualquer outro), coloque-o no impl.

Além disso, pode ser um pouco melhor colocar @Transactional nos methods na interface:

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

Por favor, dê uma olhada no link abaixo, que ilustra o problema com um exemplo simples, mas explicativo:

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

Intereting Posts