Java Reflection – dynamiczne Proxy

używając Java Reflection tworzysz dynamiczne implementacje interfejsów w czasie wykonywania. Robisz to używając klasy java.lang.reflect.Proxy. Nazwa tej klasy jest powodem, dla którego określam te dynamiczne implementacje interfejsu jako dynamiczne proxy. Dynamiczne proxy mogą być używane do wielu różnych celów, np. połączenia z bazą danych i zarządzania transakcjami, dynamicznych obiektów mock do testowania jednostek i innych celów przechwytywania metod podobnych do AOP.

Tworzenie serwerów proxy

dynamiczne Serwery Proxy tworzy się przy użyciu metody Proxy.newProxyInstance(). Metody newProxyInstance() przyjmują 3 parametry:

  1. ClassLoader czyli “Ładowanie” dynamicznej klasy proxy.
  2. tablica interfejsów do zaimplementowania.
  3. i InvocationHandler aby przekazać wszystkie metody wywołania na serwerze proxy do.

oto przykład:

po uruchomieniu tego kodu zmienna proxy zawiera dynamiczną implementację interfejsu MyInterface. Wszystkie wywołania do serwera proxy będą przekazywane do implementacji handler ogólnego interfejsu InvocationHandler. InvocationHandler ‘ S są objęte w następnej sekcji.

InvocationHandler ‘ s

jak wspomniano wcześniej, musisz przekazać implementację InvocationHandler do metody Proxy.newProxyInstance(). Wszystkie wywołania metod do dynamicznego proxy są przekazywane do tej implementacji InvocationHandler. Oto jak wygląda interfejs InvocationHandler :

public interface InvocationHandler{ Object invoke(Object proxy, Method method, Object args) throws Throwable;}

oto przykładowa implementacja:

public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object args) throws Throwable { //do something "dynamic" }}

parametr proxy przekazany do metody invoke()jest dynamicznym obiektem proxy implementującym interfejs. Najczęściej nie potrzebujesz tego obiektu.

obiekt Method przekazany do metody invoke() przedstawia metodę wywołaną w interfejsie implementowanym przez dynamiczne proxy. Z obiektu Method można uzyskać nazwę metody, typy parametrów, typ zwracany, itd. Więcej informacji można znaleźć w tekście dotyczącym metod.

tablica Object args zawiera wartości parametrów przekazywane do serwera proxy, gdy została wywołana metoda w zaimplementowanym interfejsie. Notatka: Elementy podstawowe (int, long itd) w zaimplementowanym interfejsie są opakowane w ich odpowiedniki obiektowe (Integer, Long itd.).

znane przypadki użycia

dynamiczne proxy są znane do co najmniej następujących celów:

  • połączenie z bazą danych i zarządzanie transakcjami
  • dynamiczne makiety obiektów do testowania jednostkowego
  • adaptacja kontenera DI do niestandardowych interfejsów fabrycznych
  • Przechwytywanie metody AOP

połączenie z bazą danych i zarządzanie transakcjami

Spring Framework ma proxy transakcji, które mogą uruchamiać i zatwierdzać / wycofywać transakcję za Ciebie. Jak to działa jest opisane bardziej szczegółowo w tekście zaawansowane połączenia i rozgraniczenia transakcji i propagacji, więc opiszę to tylko krótko.

dynamiczne makiety obiektów do testowania jednostek

narzędzia do testowania motyli wykorzystują dynamiczne proxy do implementacji dynamicznych wycinków, moków i proxy do testowania jednostek. Podczas testowania klasy A, która używa innej klasy B (interfejs naprawdę), możesz przekazać makietę implementacji B Do a zamiast prawdziwego B. Wszystkie wywołania metod na B są teraz rejestrowane i można ustawić, jakie wartości zwracane ma zwracać makieta B.

ponadto narzędzia do testowania motylków pozwalają owinąć rzeczywiste B w makietę B, dzięki czemu wszystkie wywołania metod na makiecie są rejestrowane, a następnie przekazywane do rzeczywistego B. umożliwia to sprawdzenie, jakie metody zostały wywołane NA rzeczywistym działającym B. na przykład, jeśli testujesz DAO, możesz owinąć połączenie z bazą danych makietą. DAO nie zobaczy różnicy, a DAO może odczytywać / zapisywać dane do bazy danych jak zwykle, ponieważ mock przekazuje wszystkie wywołania do bazy danych. Ale teraz możesz sprawdzić za pomocą makiety, czy DAO poprawnie używa połączenia, na przykład, czy connection.close() jest wywoływany (lub nie), jeśli tego się spodziewałeś. Zwykle nie można tego określić na podstawie wartości zwracanej DAO.

dostosowanie kontenera DI do niestandardowych interfejsów fabrycznych

kontener dependency injection Container Butterfly Container ma potężną funkcję, która pozwala na wstrzyknięcie całego kontenera do wyprodukowanych przez niego ziaren. Ale ponieważ nie chcesz zależności od interfejsu kontenera, kontener jest w stanie dostosować się do niestandardowego interfejsu fabrycznego twojego projektu. Potrzebujesz tylko interfejsu. Brak wdrożenia. Tak więc interfejs fabryczny i twoja klasa mogą wyglądać mniej więcej tak:

public interface IMyFactory { Bean bean1(); Person person(); ...}

kiedy Klasa MyAction wywołuje metody na instancji IMyFactory wstrzykniętej do jej konstruktora przez kontener, wywołania metod są tłumaczone na wywołania do metody IContainer.instance(), która jest metodą używaną do uzyskiwania instancji z kontenera. W ten sposób obiekt może używać kontenera Butterfly jako fabryki w czasie wykonywania, a nie tylko do wstrzykiwania zależności w czasie tworzenia. I to bez żadnych zależności od interfejsów specyficznych dla kontenerów Butterfly.

Przechwytywanie metod podobnych do AOP

Spring Framework umożliwia przechwytywanie wywołań metod do danego Beana, pod warunkiem, że Bean implementuje jakiś interfejs. Spring Framework otula fasolę dynamicznym serwerem proxy. Wszystkie połączenia do bean są następnie przechwytywane przez proxy. Serwer proxy może zdecydować o wywołaniu innych metod na innych obiektach przed, zamiast lub po delegowaniu wywołania metody do otoczonego bean.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.