2009-07-08 15 views
216

Chcę wiedzieć, co tak naprawdę dzieje się podczas opisywania metody za pomocą @Transactional? Oczywiście wiem, że Spring zawinie tę metodę w Transakcji.Wiosna - @Transactional - Co dzieje się w tle?

Ale mam następujące wątpliwości:

  1. Słyszałem, że wiosna tworzy klasę proxy? Czy ktoś może to wyjaśnić na więcej głębokości. Co właściwie znajduje się w tej klasie proxy? Co dzieje się z rzeczywistą klasą? I jak widzę stworzony proxy klasy sprężyny
  2. czytałem też w Dokumentach Wiosna, że:

Uwaga: Ponieważ mechanizm ten opiera się na proxy, tylko metoda „zewnętrzny” wzywa wpadającym przez proxy zostanie przechwycone. Oznacza to, że "samo-wywołanie", tj. Metoda w obiekcie docelowym wywołująca inną metodę obiektu docelowego, nie doprowadzi do rzeczywistej transakcji w czasie wykonywania, nawet jeśli wywołana metoda jest oznaczona jako @Transactional!

Źródło: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

Dlaczego tylko zewnętrzne wywołania metod będzie pod transakcji i nie metody self-inwokacja?

+1

Odpowiednia dyskusja znajduje się tutaj: http://stackoverflow.com/questions/3120143/where-to---- -ransakcja-na-na-interfejs-definicja-lub-an/3120323#3120323 –

Odpowiedz

168

To jest duży temat. Dokument źródłowy Spring poświęcony jest wielu rozdziałom. Polecam przeczytanie tych na Aspect-Oriented Programming i Transactions, ponieważ wsparcie deklaratywnej transakcji Spring używa AOP na swoim fundamencie.

Ale na bardzo wysokim poziomie, Spring tworzy proxy dla klas, które deklarują @Transactional na samej klasie lub na członkach. Proxy jest w większości niewidoczne w czasie wykonywania. Umożliwia Springowi wstrzykiwanie zachowań przed, po lub w okolicach wywołań metod do obiektu będącego w proxy. Zarządzanie transakcjami jest tylko jednym z przykładów zachowań, które można łączyć. Kontrole bezpieczeństwa są kolejnym. Możesz też podać swoje własne, np. Do logowania. Kiedy więc dodasz adnotację do metody z @Transactional, Spring dynamicznie utworzy serwer proxy, który implementuje te same interfejsy, co klasa, do której przypisujesz uwagę. A kiedy klienci wykonują połączenia do twojego obiektu, połączenia są przechwytywane, a zachowania wstrzykiwane za pośrednictwem mechanizmu proxy.

Transakcje w EJB działają podobnie, przy okazji.

Jak zaobserwowałeś, mechanizm proxy działa tylko wtedy, gdy połączenia przychodzą z jakiegoś zewnętrznego obiektu. Kiedy wykonujesz wewnętrzne połączenie wewnątrz obiektu, naprawdę nawiązujesz połączenie przez odniesienie "this", co omija proxy. Są jednak sposoby na obejście tego problemu. Wyjaśniam jedną metodę w this forum post, w której używam obiektu BeanFactoryPostProcessor BeanFactoryPostProcessor, aby wprowadzić instancję proxy w klasy "samo-odwołujące się" w środowisku wykonawczym. Zapisuję to odwołanie do zmiennej składowej o nazwie "mi". Jeśli potrzebuję wykonać wewnętrzne wywołania, które wymagają zmiany statusu transakcji wątku, przekierowuję połączenie przez proxy (np. "me.someMethod()".) Post na forum wyjaśnia bardziej szczegółowo. Zauważ, że kod BeanFactoryPostProcessor byłby teraz nieco inny, ponieważ został zapisany w ramce czasowej 1.x. wiosny. Ale mam nadzieję, że daje ci to pomysł. Mam zaktualizowaną wersję, którą prawdopodobnie mógłbym udostępnić.

+1

>> Serwer proxy jest w większości niewidoczny w środowisku wykonawczym Oh !! Jestem ciekaw ich zobaczyć :) Odpoczynek .. twoja odpowiedź była bardzo wyczerpująca. Po raz drugi mi pomagasz. Dziękuję za pomoc. – peakit

+9

Bez problemu. Możesz zobaczyć kod proxy, jeśli przejdziesz przez debugger. To prawdopodobnie najprostszy sposób. Nie ma magii; to tylko klasy w ramach pakietów wiosennych. –

+0

A jeśli metoda, która ma adnotację @Transaction implementuje interfejs, sprężyna użyje dynamicznego proxy API do wstrzykiwania proxy transakcyjnego i _nie_ używania. Wolę, aby moje transakalizowane klasy implementowały interfejsy w każdym przypadku. –

139

Gdy Spring wczytuje Twoje definicje fasoli i została skonfigurowana do wyszukiwania adnotacji @Transactional, utworzy te obiekty proxy wokół faktycznego komponentu bean. Te obiekty proxy są instancjami klas, które są automatycznie generowane w środowisku wykonawczym. Domyślne zachowanie tych obiektów proxy po wywołaniu metody jest po prostu wywołaniem tej samej metody dla komponentu "docelowego" (np. Komponentu bean).

Jednak serwery proxy mogą być również dostarczane z przechwytującymi, a gdy są obecne, te przechwytywacze będą wywoływane przez serwer proxy przed wywołaniem metody komponentu docelowego. W przypadku fasoli docelowej z adnotacją @Transactional, Spring utworzy TransactionInterceptor i przekaże go do wygenerowanego obiektu proxy. Kiedy wywołujesz metodę z kodu klienta, wywołujesz metodę na obiekcie proxy, który najpierw wywołuje TransactionInterceptor (który rozpoczyna transakcję), co z kolei wywołuje metodę na twoim komponencie bean. Po zakończeniu wywołania TransactionInterceptor zatwierdza/wycofuje transakcję. Jest przezroczysty dla kodu klienta.

Jeśli chodzi o rzecz "metoda zewnętrzna", jeśli komponent bean wywoła jedną ze swoich metod, nie będzie tego robił za pośrednictwem serwera proxy. Pamiętaj, że Spring zawija twoją fasolkę w proxy, twój bean nie ma o tym wiedzy. Tylko połączenia z "zewnątrz" twojego komponentu bean przechodzą przez serwer proxy.

Czy to pomaga?

+20

> Pamiętaj, Spring zawija twoją fasolkę w proxy, twoja fasola nie ma o tym wiedzy ** To wszystko powiedziało. Co za wspaniała odpowiedź. Dzięki za pomoc. ** – peakit

+0

Doskonałe wyjaśnienie dla proxy i przechwytywaczy. Teraz rozumiem wiosenne implementowanie obiektu proxy, aby przechwytywać wywołania do komponentu docelowego. Dziękuję Ci! – dharag

+5

Odpowiedź jest tak wielka, że ​​po prostu starałam się ją przedstawić tylko po to, aby otrzymać komunikat o błędzie, który już wcześniej wznowiłem! – Mustafa

20

Jako osoba wizualna lubię ważyć schemat sekwencji wzoru proxy. Jeśli nie wiesz, jak odczytywać strzałki, czytam pierwszą z nich w ten sposób: Client wykonuje Proxy.method().

  1. Klient wywołuje metodę na cel ze swojego punktu widzenia i jest cicho przechwycone przez pełnomocnika
  2. Jeżeli przed aspektem jest zdefiniowany, pełnomocnik będzie wykonywał
  3. Następnie rzeczywisty sposób (target) jest wykonywana
  4. po powrocie i po rzucanie są opcjonalne elementy, które są wykonywane po powrocie sposobu i/lub sposób generuje wyjątek
  5. Następnie serwer pośredniczący wykonuje po aspekcie (jeśli wyżej)
  6. Wreszcie wraca proxy do klienta wywołującego

Proxy Pattern Sequence Diagram (pozwolono mi opublikować zdjęcie pod warunkiem, że wspominałem swoje początki. Autor: Noel Vaes, strona internetowa: www.noelvaes.eu)

0

Najprostszą odpowiedzią jest na dowolną metodę, którą deklarujesz @Transactional, granica rozpoczęcia transakcji i granica kończy się po zakończeniu metody.

Jeśli używasz wywołania JPA, wszystkie zatwierdzenia są w tej granicy transakcji. Powiedzmy, że zapisujesz encję1, encję2 i encję3. Teraz, podczas zapisywania encji3, występuje wyjątek, ponieważ jako enitiy1 i entity2 występuje ta sama transakcja, więc encje1 i encja2 zostaną wycofane z jednostką3.

Transakcja: (entity1.save, entity2.save, entity3.save). Każdy wyjątek spowoduje wycofanie wszystkich transakcji JPA z DB. Wewnętrznie transakcje JPA są używane przez Spring.