2009-07-08 19 views
216

Voglio sapere che cosa succede realmente quando annoti un metodo con @Transactional? Ovviamente, so che Spring avvolgerà quel metodo in una Transazione.Spring - @Transactional - Cosa succede in background?

Ma, ho i seguenti dubbi:

  1. ho sentito che la primavera crea una classe procura? Qualcuno può spiegare questo in più profondità. Che cosa risiede effettivamente in quella classe proxy? Cosa succede alla classe attuale? E come posso vedere Classe Proxied creato Primavera
  2. ho letto anche in documenti di primavera che:

Nota: Dal momento che questo meccanismo si basa sulle deleghe, unico metodo 'esterna' chiamate provenienti attraverso il proxy verrà intercettato. Ciò significa che "autoinvocazione", cioè un metodo all'interno dell'oggetto target che chiama un altro metodo dell'oggetto target, non porterà a una transazione effettiva in fase di esecuzione anche se il metodo richiamato è contrassegnato con @Transactional!

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

Perché solo le chiamate di metodo esterne sarà sotto delle transazioni e non i metodi di auto-invocazione?

+1

La discussione pertinente è disponibile qui: http://stackoverflow.com/questions/3120143/where-should-i-put-transactional-annotation-at-an-interface-definition-or-at/an2031323#3120323 –

risposta

168

Questo è un grande argomento. Il documento di riferimento di Spring dedica più capitoli ad esso. Raccomando di leggere quelli su Aspect-Oriented Programming e Transactions, poiché il supporto dichiarativo delle transazioni di Spring utilizza AOP alla sua fondazione.

Ma a un livello molto alto, Spring crea dei proxy per le classi che dichiarano @Transactional sulla classe stessa o sui membri. Il proxy è per lo più invisibile in fase di runtime. Fornisce a Spring un modo per iniettare comportamenti prima, dopo o attorno a chiamate di metodi nell'oggetto che viene sottoposto a proxy. La gestione delle transazioni è solo un esempio dei comportamenti che possono essere collegati. I controlli di sicurezza sono un altro. E puoi anche fornire il tuo, per cose come la registrazione. Pertanto, quando annoti un metodo con @Transactional, Spring crea dinamicamente un proxy che implementa le stesse interfacce della classe che stai annotando. Quando i client effettuano chiamate nell'oggetto, le chiamate vengono intercettate e i comportamenti vengono iniettati tramite il meccanismo proxy.

Le transazioni in EJB funzionano allo stesso modo, tra l'altro.

Come osservato, attraverso, il meccanismo proxy funziona solo quando le chiamate arrivano da un oggetto esterno. Quando si effettua una chiamata interna all'interno dell'oggetto, si effettua una chiamata tramite il riferimento "questo", che ignora il proxy. Ci sono modi per aggirare questo problema, comunque. Spiego un approccio in this forum post in cui utilizzo un oggetto BeanFactoryPostProcessor per iniettare un'istanza del proxy in classi "autoreferenziali" in fase di runtime. Ho salvato questo riferimento a una variabile membro denominata "me". Quindi, se devo effettuare chiamate interne che richiedono una modifica dello stato della transazione del thread, indirizzo la chiamata attraverso il proxy (ad esempio "me.someMethod()".) Il post del forum spiega in modo più dettagliato. Si noti che il codice BeanFactoryPostProcessor sarebbe un po 'diverso ora, come è stato scritto di nuovo nel timeframe Spring 1.x. Ma spero che ti dia un'idea. Ho una versione aggiornata che potrei probabilmente rendere disponibile.

+1

>> Il proxy è per lo più invisibile in fase di esecuzione Oh !! Sono curioso di vederli :) Riposo .. la tua risposta è stata molto completa. Questa è la seconda volta che mi stai aiutando ... grazie per tutto l'aiuto. – peakit

+9

Nessun problema. Puoi vedere il codice del proxy se passi con un debugger. Questo è probabilmente il modo più semplice. Non c'è magia; sono solo classi nei pacchetti di primavera. –

+0

E se il metodo che ha l'annotazione @Transaction sta implementando un'interfaccia, la molla utilizzerà l'API proxy dinamico per iniettare la transazione e _non_ utilizzare i proxy. Preferisco che le mie classi transazionali implementino le interfacce in ogni caso. –

139

Quando Spring carica le definizioni dei bean ed è stato configurato per cercare le annotazioni @Transactional, creerà questi oggetti proxy attorno al bean effettivo. Questi oggetti proxy sono istanze di classi che vengono generate automaticamente in fase di runtime. Il comportamento predefinito di questi oggetti proxy quando viene invocato un metodo è solo per invocare lo stesso metodo sul bean "target" (ad esempio il bean).

Tuttavia, i proxy possono anche essere forniti con gli intercettori e, quando presenti, questi interceptor verranno richiamati dal proxy prima che invochi il metodo del bean di destinazione. Per i bean di destinazione annotati con @Transactional, Spring creerà un TransactionInterceptor e lo passerà all'oggetto proxy generato. Pertanto, quando si chiama il metodo dal codice client, si chiama il metodo sull'oggetto proxy, che prima richiama TransactionInterceptor (che inizia una transazione), che a sua volta richiama il metodo sul bean di destinazione. Al termine dell'invocazione, TransactionInterceptor esegue il commit/rollback della transazione. È trasparente per il codice cliente.

Per quanto riguarda il metodo "metodo esterno", se il bean richiama uno dei propri metodi, non lo farà tramite il proxy. Ricorda, Spring avvolge il tuo bean nel proxy, il tuo bean non ne ha conoscenza. Solo le chiamate da "esterno" al tuo bean passano attraverso il proxy.

Questo aiuto?

+20

> Ricorda che Spring racchiude il tuo bean nel proxy, il tuo bean non ne è a conoscenza ** Questo ha detto tutto. Che bella risposta. Grazie per l'aiuto. ** – peakit

+0

Grande spiegazione, per il proxy e gli intercettori. Ora capisco primavera implementare un oggetto proxy per intercettare le chiamate a un bean di destinazione. Grazie! – dharag

+5

La risposta è così grande che ho appena provato a svenderlo solo per essere presentato con un messaggio di errore che ho già svalutato prima! – Mustafa

20

Come persona visiva, mi piace pesare con un diagramma di sequenza del modello proxy. Se non sai leggere le frecce, leggo il primo in questo modo: Client esegue Proxy.method().

  1. Il client chiama un metodo sul bersaglio dalla sua prospettiva, ed è intercettato silenziosamente dal proxy
  2. Se un aspetto prima definito, il proxy lo esegue
  3. Quindi, il metodo effettivo (target) viene eseguita
  4. dopo rinvio e di post-lancio sono aspetti facoltativi che sono eseguito dopo la restituzione del metodo e/o se il metodo genera eccezione
  5. dopo di che, il proxy esegue il dopo aspetto (se definito)
  6. Infine i proxy restituisce al client chiamante

Proxy Pattern Sequence Diagram (mi è stato permesso di inviare la foto a condizione che ho menzionato le sue origini. Autore: Noel Vaes, sito web: www.noelvaes.eu)

0

La risposta più semplice è,, su qualsiasi metodo dichiari @Transactional il limite della transazione inizia e il limite termina quando il metodo termina.

Se si utilizza la chiamata JPA, tutti i commit si trovano in questo limite di transazione. Diciamo che stai salvando entità1, entità2 e entità3. Ora, mentre si salva un'entità3, si verifica un'eccezione quando enitiy1 e entity2 si trovano nella stessa transazione, quindi entità1 e entità2 eseguiranno il rollback con entity3.

Transazione: (entity1.save, entity2.save, entity3.save). Qualsiasi eccezione comporterà il rollback di tutte le transazioni JPA con DB. La transazione JPA interna viene utilizzata da Spring.

Problemi correlati