Alternatieven voor java.lang.reflecteren.Proxy voor het maken van proxy ‘ s van abstracte klassen (in plaats van interfaces)

Volgens de documentatie:

[java.lang.reflect.]Proxy biedt statische methoden voor
het maken van dynamische proxy klassen en
gevallen, en het is ook de
superklasse van alle dynamische proxy
klassen gemaakt door deze methoden.

De newProxyMethod methode (verantwoordelijk voor het genereren van de dynamische proxy ‘ s) heeft de volgende handtekening:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                             throws IllegalArgumentException

Helaas, dit voorkomt dat één van het genereren van een dynamische proxy die breidt een specifieke abstracte klasse (in plaats van de uitvoering van specifieke interfaces). Dit is logisch, gezien het feit java.lang.reflect.Proxy is “de superklasse van alle dynamische proxy ‘s”, aldus te voorkomen dat een andere klasse van de superklasse.

Daarom zijn er alternatieven voor java.lang.reflect.Proxy dat kan het dynamisch genereren proxy ‘ s die erven van een specifieke abstracte klasse, het omleiden van alle oproepen naar de abstracte methoden om de aanroep-handler?

Bijvoorbeeld, stel dat ik een abstracte klasse Dog:

public abstract class Dog {

    public void bark() {
        System.out.println("Woof!");
    }

    public abstract void fetch();

}

Is er een klasse die me in staat stelt om het volgende te doen?

Dog dog = SomeOtherProxy.newProxyInstance(classLoader, Dog.class, h);

dog.fetch(); //Will be handled by the invocation handler
dog.bark();  //Will NOT be handled by the invocation handler

 

2 Replies
  1. 111

    Het kan worden gedaan met behulp van Javassist (zie ProxyFactory) of CGLIB.

    Adam ‘ s voorbeeld van het gebruik van Javassist:

    Ik Adam (Paynter) schreef deze code met behulp van Javassist:

    ProxyFactory factory = new ProxyFactory();
    factory.setSuperclass(Dog.class);
    factory.setFilter(
        new MethodFilter() {
            @Override
            public boolean isHandled(Method method) {
                return Modifier.isAbstract(method.getModifiers());
            }
        }
    );
    
    MethodHandler handler = new MethodHandler() {
        @Override
        public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
            System.out.println("Handling " + thisMethod + " via the method handler");
            return null;
        }
    };
    
    Dog dog = (Dog) factory.create(new Class<?>[0], new Object[0], handler);
    dog.bark();
    dog.fetch();

    Die produceert deze uitvoer:

    Woof! 
    Behandeling public abstract void mock.Hond.fetch() via de methode van de handler 
    
    • +1: Precies wat ik nodig heb! Ik zal het bewerken van uw antwoord met mijn voorbeeld-code.
    • proxyFactory.setHandler() is verouderd. Gebruik proxy.setHandler.
    • is het object “Hond” een uitvoering of een interface in de bovenstaande code?
  2. -7

    Wat je kan doen in zo een geval is het hebben van een proxy-handler zal omleiden van oproepen naar bestaande methoden van uw abstracte klasse.

    U natuurlijk zal hebben om te programmeren, maar het is heel simpel. Voor het maken van uw Proxy, je moet hem een InvocationHandler. U zult dan alleen maar te controleren is de methode van het type in de beroep(..) methode van uw inroepen van de handler. Maar pas op : je moet controleren is de methode van het type op het onderliggende object dat is gekoppeld aan uw behandelaar, en niet tegen de gedeclareerde type van uw abstracte klasse.

    Ik neem als voorbeeld uw hond klasse, uw inroepen handler aanroepen van methode kan er als volgt uitzien (met een bestaand gekoppeld hond subklasse genoemd .. nou … dog)

    public void invoke(Object proxy, Method method, Object[] args) {
        if(!Modifier.isAbstract(method.getModifiers())) {
            method.invoke(dog, args); //with the correct exception handling
        } else {
            //what can we do with abstract methods ?
        }
    }

    Echter, er is iets dat houd mij af : ik heb gesproken over een dog object. Maar, als de Hond klasse is abstract, je kunt niet gevallen, zodat u bestaande subklassen. Bovendien, als een strenge controle van de Proxy-bron-code onthult, kunt u ontdekken (bij Volmacht.java:362) dat het niet mogelijk is om een Proxy voor een Klasse object dat niet vertegenwoordigt een interface).

    Dus, afgezien van de werkelijkheid, wat u wilt doen is dit perfect mogelijk.

    • Houd er rekening met mij, terwijl ik probeer te begrijpen uw antwoord… In mijn geval, ik wil de proxy class (gegenereerd tijdens runtime) worden de subklasse van Dog (bijvoorbeeld, ik ben niet uitdrukkelijk schriftelijk een Poodle klasse implementeert fetch()). Daarom is er geen dog variabele te roepen van de methoden op… Sorry als ik verwarrend, ik denk dat dit meer dan een beetje meer.
    • je kunt niet dynamisch maken van de subklassen tijdens runtime zonder enige bytecode manipulatie (CGLib ik denk dat iets als dit). Het korte antwoord is dat de dynamische proxies ondersteunen interfaces, maar niet abstracte klassen, omdat het twee heel verschillende begrippen. Het is bijna onmogelijk om te denken aan een manier om dynamisch proxy abstracte klassen in een gezonde manier.
    • Ik begrijp dat wat ik vraag vereist bytecode manipulatie (in feite heb ik al geschreven dat een oplossing voor mijn probleem met ASM). Ik begrijp ook dat Java-dynamische proxies ondersteunen alleen interfaces. Misschien is mijn vraag was niet helemaal duidelijk – ik ben met de vraag of er sprake is andere klasse (dat is iets anders dan java.lang.reflect.Proxy) beschikbaar die doet wat ik nodig heb.
    • Goed, om een lang verhaal kort … geen (althans in standaard Java-klassen). Met behulp van het toetsenbord manipulatie, de sky is the limit !
    • Hoort, hoort! Ik persoonlijk hou van bytecode manipulatie (zoals ik al zei, ik heb al de oplossing met behulp van ASM)! Ik hoopte dat er al een beproefde oplossing. 🙂
    • Maar, java.lang.reflecteren.Proxy maakt gebruik van bytecode generatie intern – waarom heeft ze niet mee verder en ondersteuning klassen uitbreiden?
    • Ik downvoted want het is niet echt een antwoord op de vraag. OP al gezegd dat hij wil proxy een klasse, niet een interface, en is zich ervan bewust dat dat niet mogelijk is met java.lang.reflecteren.Proxy. U herhaalt dat feit en bieden geen andere oplossing.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *