Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] WeavingAdapter - how to use it?

>> If you add "-Xbootclasspath/p:<path_to_aspects.jar>" JVM option, then you can instrument inside the JDKs and also instrument already loaded classes.

Not sure that statement is quite correct.  You cannot just do that to
instrument already loaded classes - you can use the bootclasspath
option to instrument system classes that ordinarily are beyond your
reach because they have been loaded before the weaver has been
initialized.

AspectJ doesn't offer anything special in terms of instrumentation or
dynamic modification of already loaded classes.  But it attempts to
play nicely with whatever you are attempting to use to do that.  For
example if running in debug mode with -javaagent:aspectjweaver, and
you change a type that was woven through loadtime weaving, when the
debugger attempts to hotswap the new version in, the weaver will weave
it again (IIRC).  If you are reloading by discarding a classloader and
recreating it, a new weaver instance will be used for the new
classloader and do the weaving again.

> I am interested in the second option (the former afterwards maybe). How do you use this class to instrument and replace an already loaded class? I mean do you have a code snippet showing which parameters you submit to "transform" and hoow to replace an already loaded class? Specifically:
>   - Which loader do you use? A WeavingURLClassLoader or the loader the weaving target was initially loaded by?

If you were using a classloader strategy to discard/reload code and
not using -javaagent then you might use a WeavingURLClassLoader.  But
the WeavingURLClassLoader is not going to be noticing files changing
on disk that need reloading and managing the deletion/creation of the
classloader instances.

>   - Where does the byte array for the class to be woven come from?

In the basic scenario it comes from the debugger in your ide... For
other kinds of solution you have to have something noticing the class
files are changing and pushing the change in. For example the
reloading agent that Grails uses does this. It monitors the files
system, sees a .class file has changed, picks up the bytecode and
pushes into the reloading agent.  In principal the grails reloading
technology (springloaded) can be reused in a standalone setting to
achieve the reloading of woven code, but I haven't done a lot of
testing of this setup.

>     Can I get the class's bytes somehwere from memory or do I need
>     to re-load the actual .class file from disk/URL/JAR/whatever?

A monitoring solution will be watching disk, load them from there and
pass them to the weaver to weave again, and then reload the result of
that weaving.

it is quite a complex area...

Andy

> Silviu Andrica wrote in 2009:
>> Hello,
>>
>> I looked through AspectJ's Load Time Weaver and I combined it with your code suggestion.
>> This is what I got out
>>
>> import java.lang.instrument.ClassFileTransformer;
>> import java.lang.instrument.IllegalClassFormatException;
>> import java.security.ProtectionDomain;
>> import java.util.ArrayList;
>> import java.util.Arrays;
>> import java.util.List;
>> import java.util.Map;
>> import java.util.concurrent.ConcurrentHashMap;
>>
>> import org.aspectj.weaver.loadtime.Aj;
>> import org.aspectj.weaver.loadtime.DefaultWeavingContext;
>> import org.aspectj.weaver.loadtime.definition.Definition;
>> import org.aspectj.weaver.tools.WeavingAdaptor;
>>
>> public class AspectJLTW implements ClassFileTransformer {
>>
>>       private class MonitorWeavingContext extends DefaultWeavingContext {
>>
>>               public MonitorWeavingContext(ClassLoader loader) {
>>                       super(loader);
>>               }
>>
>>               @Override
>>               public List getDefinitions(ClassLoader loader, WeavingAdaptor adaptor) {
>>                       List definitions = new ArrayList();
>>                       Definition d = new Definition();
>>                       d.getAspectClassNames().add(aspectName);
>>                       d.appendWeaverOptions("-Xjoinpoints:synchronization");
>>                       definitions.add(d);
>>                       return definitions;
>>               }
>>
>>       }
>>
>>       private final Map<ClassLoader, Aj> mapFromClassLoaderToAj;
>>       private final String aspectName;
>>
>>       public AspectJLTW(String aspectName) {
>>               try {
>>                       mapFromClassLoaderToAj = new ConcurrentHashMap<ClassLoader, Aj>();
>>                       this.aspectName = aspectName;
>>               } catch (Exception e) {
>>                       throw new ExceptionInInitializerError(
>>                                       "could not initialize JSR163 preprocessor due to: "
>>                                                       + e.toString());
>>               }
>>       }
>>
>>       /**
>>        * Weaving delegation
>>        *
>>        * @param loader
>>        *            the defining class loader
>>        * @param className
>>        *            the name of class beeing loaded
>>        * @param classBeingRedefined
>>        *            when hotswap is called
>>        * @param protectionDomain
>>        * @param bytes
>>        *            the bytecode before weaving
>>        * @return the weaved bytecode
>>        */
>>       public byte[] transform(ClassLoader loader, String className,
>>                       Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
>>                       byte[] bytes) throws IllegalClassFormatException {
>>               if (className.replace("/", ".").equals(aspectName))
>>                       return null;
>>               Aj aj = getInstrumenter(loader);
>>               byte[] b = aj.preProcess(className, bytes, loader);
>>               if (Arrays.equals(bytes, b))
>>                       return null;
>>               return b;
>>       }
>>
>>       private Aj getInstrumenter(ClassLoader loader) {
>>               if (mapFromClassLoaderToAj.containsKey(loader)) {
>>                       return mapFromClassLoaderToAj.get(loader);
>>               }
>>               Aj aj = new Aj(new MonitorWeavingContext(loader));
>>               mapFromClassLoaderToAj.put(loader, aj);
>>               return aj;
>>       }
>> }
>>
>> If you add "-Xbootclasspath/p:<path_to_aspects.jar>" JVM option, then you can instrument inside the JDKs and also instrument already loaded classes.
>> I tried it on Java 1.6.0_15 on Mac OSX.
>>
>> One little note: JVM complains about java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields). I suspect t has something to do with AspectJ adding extra fields. Is there a way to force inlining of the aspects?
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-users


Back to the top