Ciele
- Vyskúšať vytváranie dynamického proxy.
- Vyskúšať vytváranie proxy pomocou knižnice Javassist.
- Vyskúšať modifikovanie tried pomocou Java agentov.
Postup
Krok 1: Dynamické proxy
Úloha 1.1
Stiahnite si kostru projektu.
Projekt obsahuje 3 podprojekty:
- metrics — kostra knižnice pre zaznamenávanie počtu volaní a času vykonávania metód,
- agent — kostra implementácie Java Agenta pre automatické modifikovanie tried,
- example — príklad použitia knižnice.
Implementácia knižnice obsahuje triedu MetricsCollector, ktorá slúži na zber údajov o volaniach metód. Napríklad, metóda report(String methodName, long duration)
pridáva záznam o volaní metódy a metóda printMetrics()
vypisuje štatistiky volaní.
Úloha 1.2
Implementujte vytváranie dynamických proxy pre zaznamenávanie metrík o volaní metód.
Potrebujete implementovať metódy v triede MetricsProxy metódy:
- wrapInProxy pre vytvorenie dynamického proxy,
- MetricsIH.invoke pre meranie času vykonávanie metódy.
Na meranie času vykonávanie metódy potrebujete zaznamenať čas pred jej volaním:
long traceTimeStart = System.nanoTime();
Po vykonaní metódy zaznamenajte informácie a celkový čas vykonávania:
MetricsCollector.report(
className + "." + method.getName(),
System.nanoTime() - traceTimeStart);
Pre vyskúšanie implementácie doplňte v metóde Main.main príkladu vytvorenie proxy a volanie metódy na ňom:
Hello helloProxy = (Hello) MetricsProxy.wrapInProxy(hello);
helloProxy.sayHello();
Krok 2: Proxy pomocou Javassist
Okrem zabudovaného mechanizmu dynamických proxy, podobný efekt môžeme dosiahnuť aj pomocou externých knižníc, napríklad Javassist Výhodou je to, že pomocou Javassist môžeme vytvoriť proxy, ktoré dedí od zadanej triedy a nielen implementuje rozhrania.
Úloha 2.1
Implementujte novú verziu proxy pomocou knižnice Javassist.
Na vytvorenie proxy použite triedu ProxyFactory. Na spracovanie volaní metód musíte vytvoriť objekt implementujúci rozhranie MethodHandler.
Na overenie fungovania tohto riešenia skúste zabaliť do proxy objekt greater triedy ListGreater, ktorá neimplementuje žiadne rozhranie.
Krok 3: Java agenty
Alternatívou k vytváraniu proxy počas behu aplikácie je modifikácia bajtkódu priamo pri jej spúšťaní. Na to môžeme využiť mechanizmus Java Agentov.
Úloha 3.1
Skúste pripojiť pripraveného Java agenta pri spúšťaní aplikácie.
Pripojenie agenta sa zapína prepínačom -javaagent
, napríklad
-javaagent:agent/target/agent-1.0-SNAPSHOT.jar
Poznámka
Pred samotným spustením potrebujete vytvoriť súbory JAR. Použite pritom príkaz mvn package
. V IntelliJ IDEA môžete v paneli Maven zvoliť Lifecycle→Package.
Poznámka
V IntelliJ IDEA môžete tento prepínač nastaviť v nastavenia spúšťania (Run Configuration):
Po spustení aplikácie by ste mali vidieť výpis zo spusteného agenta.
Úloha 3.2
Vytvorte Java agenta, ktorý bude modifikovať kód načítavaných tried tak, aby zaznamenávali metriky o vykonávaní metód. Modifikovanie sa má týkať všetkých metód s anotáciou CollectMetrics.
Použite knižnicu Javaasist na to, aby ste doplnili meranie času a zaznamenanie volania priamo do metód. Môžete využiť napríklad tieto metódy:
- ClassPool.getOrNull() — načítanie kódu triedy,
- CtClass.getDeclaredBehaviors() — získanie zoznamu metód a konštruktorov triedy,
- CtBehavior.addLocalVariable() — pridanie premennej do metódy,
- CtBehavior.insertBefore() — pridanie kódu na začiatok metódy,
- CtBehavior.insertAfter() — pridanie kódu na koniec metódy.
- CtClass.toBytecode() — vygenerovanie bajtkódu modifikovanej triedy.
Zdroje
- Ivan Yurchenko. Java agents, Javassist and Byte Buddy
- Package java.lang.instrument