Laden von instrumentierten Klassen in und durch OSGi-Bundles

justincaseof

Grünschnabel
Hallo Forum!

Ich instrumentiere Class-Files mit Hilfe des ASM-Frameworks. Statisch funktioniert die ganze Geschichte schon recht zufriedenstellend.
Ich möchte nun jedoch dynamisch bestimmte Klassen eines OSGi Bundles instrumentieren. Darum soll sich ein Bundle kümmern, welches quasi das Laden (und Instrumentieren) von Klassen für andere Bundles übernimmt.
Ich habe bereits vom java.lang.instrument Package gelesen; jedoch ist mir nicht ganz klar, ob und wie das zusammen mit dem OSGi-Framework funktioniert.

Viele Grüße,
der Tobi
 
Zuletzt bearbeitet:
Hallo,

also wenn du das Instrumentieren mit ASM über java.lang.instrument.Instrumentation via ClassFileTransfomer erledigst, sollte das kein Problem sein. Der Transformer wird IMHO aktiv wann immer ein loadClass bzw. defineClass von einem ClassLoader gemacht wird. Das ist im Prinzip noch eine Ebene unter den OSGi ClassLoading Mechanismus (d.h. die OSGi BundleClassLoader werden dann auch unter der Haube diesen ClassFileTransformer anwerfen). Sogar zur Laufzeit generierte Klassen (Dynamic Proxies) können entsprechend Instrumentiert werden.

Java:
package de.tutorials;

import java.lang.instrument.Instrumentation;

public class InstrumentationHelper {

    private static Instrumentation instrumentation;

    public static void premain(String agentArgs, Instrumentation inst) {
        instrumentation = inst;
    }

    public static Instrumentation getInstrumentation() {
        return instrumentation;
    }
}

Java:
package de.tutorials;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.ProtectionDomain;

public class DynamicInstrumentationExample {
    public static void main(String[] args) {
        System.out.println(InstrumentationHelper.getInstrumentation());
        
        InstrumentationHelper.getInstrumentation().addTransformer(new ClassFileTransformer(){

            @Override
            public byte[] transform(ClassLoader loader, String className,
                    Class<?> classBeingRedefined,
                    ProtectionDomain protectionDomain, byte[] classfileBuffer)
                    throws IllegalClassFormatException {
                
                System.out.println("transform: " + className);
                
                return classfileBuffer;
            }
            
        });
        
        IFoo foo = (IFoo)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IFoo.class}, new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                System.out.println("method: " + method);
                return null;
            }
            
        });
        
        System.out.println(foo);
        foo.op();
        
    }
    
    static interface IFoo{
        void op();
    }
}

Manifest:
Code:
Manifest-Version: 1.0
Premain-Class: de.tutorials.InstrumentationHelper
Can-Redefine-Classes: true
Main-Class: de.tutorials.DynamicInstrumentationExample

Ausgabe:
Code:
C:\>java -javaagent:instrumentation.jar de.tutorials.DynamicInstrumentationExample
sun.instrument.InstrumentationImpl@1ded0fd
transform: de/tutorials/DynamicInstrumentationExample$IFoo
transform: de/tutorials/DynamicInstrumentationExample$2
transform: java/lang/reflect/Proxy
transform: java/util/WeakHashMap
transform: java/util/WeakHashMap$Entry
transform: java/util/Arrays$ArrayList
transform: java/util/AbstractList$Itr
transform: sun/misc/ProxyGenerator
transform: sun/security/action/GetBooleanAction
transform: java/lang/InterruptedException
transform: sun/misc/ProxyGenerator$ConstantPool
transform: sun/misc/ProxyGenerator$ProxyMethod
transform: java/lang/Class$MethodArray
transform: java/util/HashMap$Values
transform: java/util/HashMap$ValueIterator
transform: java/util/HashMap$HashIterator
transform: sun/misc/ProxyGenerator$MethodInfo
transform: sun/misc/ProxyGenerator$ConstantPool$ValueEntry
transform: sun/misc/ProxyGenerator$ConstantPool$Entry
transform: java/io/DataOutputStream
transform: java/io/DataOutput
transform: sun/misc/ProxyGenerator$ConstantPool$IndirectEntry
transform: sun/misc/ProxyGenerator$FieldInfo
transform: java/lang/Void
transform: sun/misc/ProxyGenerator$PrimitiveTypeInfo
transform: sun/misc/ProxyGenerator$ExceptionTableEntry
transform: de/tutorials/$Proxy0
transform: java/lang/reflect/UndeclaredThrowableException
transform: java/lang/NoSuchMethodException
method: public java.lang.String java.lang.Object.toString()
null
method: public abstract void de.tutorials.DynamicInstrumentationExample$IFoo.op()
transform: java/util/IdentityHashMap$KeySet
transform: java/util/IdentityHashMap$KeyIterator
transform: java/util/IdentityHashMap$IdentityHashMapIterator
transform: java/io/DeleteOnExitHook
transform: java/util/LinkedHashSet
transform: java/util/HashMap$KeySet
transform: java/util/LinkedHashMap$KeyIterator
transform: java/util/LinkedHashMap$LinkedHashIterator

Nichts anderes macht im Prinzip die Eclipse / AspectJ sowie die Spring / AspectJ integration bei Load-time weaving -> die verwenden da auch einfach einen entsprechenden ClassFileTransformer (WeavingTransformer: http://static.springframework.org/s...strument/classloading/WeavingTransformer.html ) Da kannst du dir abschauen wie man sowas macht.
Ansonsten schau mal hier:
http://www.tutorials.de/forum/java/...-eclipse-rcp-view-mit-aspectj-und-spring.html
http://www.tutorials.de/forum/java/...lung-platformspezifischer-objektgroessen.html

Gruß Tom
 
Zurück