a Java Reflection használatával dinamikus implementációkat hozhat létre futásidőben. Ezt a java.lang.reflect.Proxy
osztály használatával teheti meg. Ennek az osztálynak a neve az, amiért ezeket a dinamikus interfész implementációkat dinamikus proxyknak nevezem. A dinamikus proxyk sokféle célra használhatók, pl. adatbázis-kapcsolat és tranzakciókezelés, dinamikus mock objektumok egységteszteléshez és más AOP-szerű metódus-elfogási célokra.
proxyk létrehozása
dinamikus proxykat hoz létre az Proxy.newProxyInstance()
módszerrel. A newProxyInstance()
módszerek 3 paramétert vesznek fel:
- a
ClassLoader
, azaz a dinamikus proxy osztály “betöltése”. - a megvalósítandó interfészek tömbje.
- An
InvocationHandler
a proxy összes metódusának továbbításához.
íme egy példa:
a kód futtatása után a proxy
változó a MyInterface
interfész dinamikus megvalósítását tartalmazza. A proxyhoz intézett összes hívás az Általános handler
interfész InvocationHandler
implementációjához kerül továbbításra. InvocationHandler által lefedett i a következő részben.
InvocationHandler ‘ s
mint korábban említettük, át kell adnia egy InvocationHandler
implementációt a Proxy.newProxyInstance()
metódusnak. A dinamikus proxyhoz intézett összes metódushívás erre a InvocationHandler
megvalósításra kerül. Így néz ki a InvocationHandler
felület:
public interface InvocationHandler{ Object invoke(Object proxy, Method method, Object args) throws Throwable;}
íme egy példa a megvalósításra:
public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object args) throws Throwable { //do something "dynamic" }}
a proxy
paraméter, amelyet a invoke()
metódusnak adtak át, az interfészt megvalósító dinamikus proxyobjektum. Leggyakrabban nincs szüksége erre az objektumra.
a Method
objektum, amelyet a invoke()
metódusnak adtak át, azt a metódust képviseli, amelyet az interfészen a dinamikus proxyalkalmazások hívnak meg. A Method
objektumból megkaphatja a metódus nevét, paraméter típusait, visszatérési típusát stb. További információkért lásd a módszerek szövegét.
a Object args
tömb tartalmazza a proxynak átadott paraméterértékeket, amikor a megvalósított interfészen lévő metódust meghívták. Megjegyzés: a megvalósított felületen lévő primitívek (int, long stb.) Az objektum megfelelőikbe vannak csomagolva (Integer, Long stb.).
ismert felhasználási esetek
a dinamikus proxykat legalább a következő célokra használják:
- adatbázis-kapcsolat és Tranzakciókezelés
- dinamikus Mock objektumok Egységteszteléshez
- di konténer adaptálása egyéni gyári interfészekhez
- AOP-szerű módszer lehallgatás
adatbázis-kapcsolat és Tranzakciókezelés
a Spring keretrendszer rendelkezik egy tranzakciós proxyval, amely elindíthat és végrehajthat / visszavonhat egy tranzakciót az Ön számára. Ennek működését részletesebben az Advanced Connection and Transaction Demarkation and Propagation szöveg írja le, ezért csak röviden írom le. A hívássorozat ezen a módon válik valamivé:
dinamikus Mock objektumok az egység teszteléséhez
a Butterfly Testing Tools dinamikus proxykat használ a dinamikus csonkok, gúnyok és proxyk megvalósításához az egység teszteléséhez. Egy olyan A osztály tesztelésekor, amely egy másik B osztályt használ (interfész valóban), átadhatja a B ál implementációját A-nak a valódi B helyett. Az összes B metódushívás rögzítésre kerül, és beállíthatja, hogy milyen visszatérési értékeket adjon vissza a mock B.
továbbá pillangó vizsgálati eszközök lehetővé teszik, hogy lezárja a valódi B egy ál B, úgy, hogy az összes módszer felhívja a ál rögzítésre kerül, majd továbbítja az igazi B. Ez lehetővé teszi, hogy ellenőrizze, milyen módszereket hívtak egy valós működő B. például, ha a tesztelés egy DAO akkor csomagolja az adatbázis-kapcsolat egy ál. A DAO nem fogja látni a különbséget, és a DAO a szokásos módon képes adatokat olvasni/írni az adatbázisba, mivel a mock minden hívást továbbít az adatbázisba. De most ellenőrizheti a mock segítségével, hogy a DAO megfelelően használja-e a kapcsolatot, például ha a connection.close()
hívják (vagy nem hívják), ha erre számítottál. Ezt általában nem lehet meghatározni a Dao visszatérési értékéből.
a DI konténer adaptálása az egyedi gyári interfészekhez
a dependency injection container Butterfly Container erőteljes funkcióval rendelkezik, amely lehetővé teszi az egész tartály befecskendezését az általa termelt Babba. De mivel nem akar függőséget a konténer interfésztől, a konténer képes alkalmazkodni a tervezés egyéni gyári felületéhez. Csak az interfészre van szüksége. Nincs megvalósítás. Így a gyári felület és az osztályod valahogy így nézhet ki:
public interface IMyFactory { Bean bean1(); Person person(); ...}
amikor a MyAction
osztály meghívja a IMyFactory
példány metódusait, amelyeket a tároló injektál a konstruktorába, a metódushívások a IContainer.instance()
metódusra történő hívásokká alakulnak, amely módszer a példányok beszerzésére szolgál a tárolóból. Így egy objektum futásidőben gyárként használhatja a Butterfly Container-t, nem pedig csak azért, hogy függőségeket injektáljon önmagába a létrehozás idején. És ez anélkül, hogy bármilyen függőség bármilyen pillangó konténer specifikus interfészek.
AOP-szerű módszer lehallgatás
a Spring keret lehetővé teszi, hogy lehallgatják módszer hívások egy adott bean, feltéve, hogy bean megvalósítja valamilyen interfész. A tavaszi keret a babot dinamikus proxyba csomagolja. Ezután a meghatalmazott elfogja a babhoz intézett összes hívást. A proxy dönthet úgy, hogy más módszereket hív meg más objektumokon, akár a metódushívás delegálása előtt, helyett vagy után a Bean csomagolva.