JDK Dynamiczne proxy może proxy tylko przez interfejs (więc Twoja klasa docelowa musi zaimplementować interfejs, który jest następnie implementowany przez klasę proxy).
CGLIB (i javassist) mogą tworzyć proxy przez tworzenie podklas. W tym scenariuszu proxy staje się podklasą klasy docelowej. Nie potrzeba interfejsów.
Więc dynamiczne proxy Java mogą proxy: public class Foo implements iFoogdzie CGLIB może proxy:public class Foo
EDYTOWAĆ:
Powinienem o tym wspomnieć, ponieważ javassist i CGLIB używają proxy przez podklasy, że jest to powód, dla którego nie można zadeklarować ostatecznych metod ani uczynić klasy ostateczną, gdy używa się frameworków, które na tym polegają. To powstrzymałoby te biblioteki przed zezwalaniem na podklasy twojej klasy i nadpisywanie twoich metod.
dzięki..!! ale byłoby pomocne, gdybyś mógł mi podać jeden przykładowy kod (lub Link), aby w niektórych przypadkach zilustrować jego użycie w porównaniu z innym .. !!!
Zauważ, że proxy JDK w rzeczywistości rezygnują z proxy dla IFoo, a nie dla żadnego Foo dla żadnego rodzaju. To dość ważna różnica. Ponadto serwery proxy cglib są pełnymi podklasami - skorzystaj z tego! Użyj filtrów, aby użyć tylko tych metod proxy, na których Ci zależy, i użyj bezpośrednio wygenerowanej klasy.
Należy również zauważyć, że tworzenie podklasy CGLib wymaga wystarczającej wiedzy o superklasie, aby móc wywołać poprawny konstruktor z odpowiednimi argumentami. W przeciwieństwie do proxy opartego na interfejsie, który nie przejmuje się konstruktorami. To sprawia, że praca z proxy CGLib jest mniej „automatyczna” niż z proxy JDK. Kolejną różnicą jest koszt „stosu”. Proxy JDK zawsze generuje dodatkowe ramki stosu na wywołanie, podczas gdy CGLib może nie kosztować żadnych dodatkowych ramek stosu. Staje się to coraz bardziej istotne, im bardziej złożona jest aplikacja (ponieważ im większy stos, tym więcej wątków pamięci zużywa).
Serwery proxy JDK pozwalają na implementację dowolnego zestawu interfejsów podczas tworzenia podklas Object. Dowolna metoda interfejsu plus Object::hashCode, Object::equalsa Object::toStringnastępnie jest przekazywana do pliku InvocationHandler. Dodatkowo java.lang.reflect.Proxyzaimplementowano standardowy interfejs biblioteki .
cglib umożliwia zaimplementowanie dowolnego zestawu interfejsów podczas tworzenia podklas dowolnej klasy, która nie jest ostateczna. Ponadto metody można opcjonalnie przesłonić, tj. Nie wszystkie metody nieabstrakcyjne muszą zostać przechwycone. Ponadto istnieją różne sposoby implementacji metody. Oferuje również InvocationHandlerklasę (w innym pakiecie), ale pozwala również wywoływać super metody przy użyciu bardziej zaawansowanych przechwytywaczy, na przykład a MethodInterceptor. Ponadto cglib może poprawić wydajność dzięki wyspecjalizowanym przechwyceniom, takim jak FixedValue. Kiedyś napisałem podsumowanie różnych przechwytywaczy dla cglib .
Różnice w wydajności
Serwery proxy JDK są implementowane raczej naiwnie z tylko jednym dyspozytorem przechwytywania, plikiem InvocationHandler. Wymaga to wysłania metody wirtualnej do implementacji, która nie zawsze może być wbudowana. Cglib pozwala na tworzenie wyspecjalizowanego kodu bajtowego, co czasami może poprawić wydajność. Oto kilka porównań implementacji interfejsu z 18 metodami pośredniczącymi:
Czas jest podawany w nanosekundach z odchyleniem standardowym w szelkach. Więcej szczegółów na temat testu porównawczego można znaleźć w samouczku Byte Buddy, w którym Byte Buddy jest bardziej nowoczesną alternatywą dla cglib. Należy również zauważyć, że cglib nie jest już aktywnie rozwijany.
Cglib jest zewnętrzną zależnością i obecnie nie jest obsługiwana. Poleganie na oprogramowaniu innych firm jest zawsze ryzykowne, więc najlepiej jest, gdy polega na nim jak najmniej osób.
W swoim blogu mówisz: „Należy jednak zachować ostrożność podczas wywoływania metody w obiekcie proxy, który jest dostarczany z metodą InvocationHandler # invoke. Wszystkie wywołania tej metody będą wysyłane za pomocą tego samego obiektu InvocationHandler i dlatego mogą powodować niekończącą się pętlę ”. Co masz na myśli?
Jeśli wywołasz metodę na obiekcie proxy, każde wywołanie jest kierowane przez nasz program obsługi wywołań. Jeśli jakikolwiek program obsługi wywołania deleguje wywołanie obiektu, następuje wspomniana rekursja.
Cześć Rafael, wiadomość niezwiązana z Twoją odpowiedzią, Pinguję o zmianę dokonaną 5 lat temu . Ponieważ cglib najwyraźniej nadal ma zatwierdzenia w 2019 r. I nie pokazuje żadnego zatrzymanego rozwoju w swoim pliku readme, usunąłem twoje oświadczenie z fragmentu tagu. Jeśli jest coś, o czym warto wspomnieć, możesz poprawić opis / fragment tagu.
Dynamiczne proxy: dynamiczne implementacje interfejsów w czasie wykonywania przy użyciu JDK Reflection API .
Przykład: Spring używa dynamicznych proxy do transakcji w następujący sposób:
Wygenerowany proxy znajduje się na szczycie fasoli. Dodaje fasoli do międzynarodowego zachowania. Tutaj proxy generuje się dynamicznie w czasie wykonywania przy użyciu JDK Reflection API.
Kiedy aplikacja zostanie zatrzymana, proxy zostanie zniszczone, a my będziemy mieć tylko interfejs i bean w systemie plików.
W powyższym przykładzie mamy interfejs. Jednak w większości implementacji interfejs nie jest najlepszy. Więc bean nie implementuje interfejsu, w takim przypadku używamy dziedziczenia:
Aby wygenerować takie proxy, Spring używa biblioteki innej firmy o nazwie CGLib .
CGLib ( C ode G eneration Lib rary ) jest zbudowany na bazie ASM , jest używany głównie do generowania komponentu bean rozszerzającego proxy i dodaje zachowanie fasoli w metodach proxy.
Spring AOP używa dynamicznych proxy JDK lub CGLIB do tworzenia proxy dla danego obiektu docelowego. (Dynamiczne proxy JDK są preferowane, gdy masz wybór).
Jeśli obiekt docelowy, który ma być proxy, implementuje co najmniej jeden interfejs, zostanie użyty dynamiczny serwer proxy JDK. Wszystkie interfejsy zaimplementowane przez typ docelowy będą proxy. Jeśli obiekt docelowy nie implementuje żadnych interfejsów, zostanie utworzony serwer proxy CGLIB.
Jeśli chcesz wymusić użycie proxy CGLIB (na przykład do proxy każdej metody zdefiniowanej dla obiektu docelowego, a nie tylko tych zaimplementowanych przez jego interfejsy), możesz to zrobić. Należy jednak wziąć pod uwagę kilka kwestii:
nie można zalecić ostatecznych metod, ponieważ nie można ich zastąpić.
Będziesz potrzebował plików binarnych CGLIB 2 w swojej ścieżce klas, podczas gdy dynamiczne proxy są dostępne z JDK. Spring automatycznie ostrzeże Cię, gdy potrzebuje CGLIB, a klasy biblioteki CGLIB nie zostaną znalezione w ścieżce klas.
Konstruktor twojego obiektu proxy zostanie wywołany dwukrotnie. Jest to naturalna konsekwencja modelu proxy CGLIB, w którym podklasa jest generowana dla każdego obiektu proxy. Dla każdej instancji proxy tworzone są dwa obiekty: rzeczywisty obiekt proxy i instancja podklasy, która implementuje poradę. To zachowanie nie jest widoczne podczas korzystania z serwerów proxy JDK. Zwykle dwukrotne wywołanie konstruktora typu proxy nie jest problemem, ponieważ zwykle mają miejsce tylko przypisania i nie ma rzeczywistej logiki w konstruktorze.
Używamy plików cookie i innych technologii śledzenia w celu poprawy komfortu przeglądania naszej witryny, aby wyświetlać spersonalizowane treści i ukierunkowane reklamy, analizować ruch w naszej witrynie, i zrozumieć, skąd pochodzą nasi goście.
Kontynuując, wyrażasz zgodę na korzystanie z plików cookie i innych technologii śledzenia oraz potwierdzasz, że masz co najmniej 16 lat lub zgodę rodzica lub opiekuna.