kennyg
kennyg

Reputation: 1059

Why is load time weaving using aspectjweaver javaagent so slow for me?

The project I'm working on is considerably large. While trying to get load time weaving working for this spring project, I was instructed to use both the spring-instrument javaagent as well as the aspectjweaver javaagent. However, I notice that when using the aspectjweaver agent, my launch time shoots up 4-6 fold. I can also see identical weave messages 4-6 times coming from ContextOverridingClassLoader.

If I remove aspectjweaver however, and only use spring-instrument, I notice my launch time decrease dramatically with only a single weave message per join point coming from AppClassLoader.

The only issue being that some specific classes are not woven (I found that this is due to the spring application context not yet being loaded before the faulty classes are loaded by the class loader, as spring is the mechanism that enables the weaving). I've found a solution of my own by creating a custom javaagent which enables weaving in the same manner that spring-instrument does, only it does so in the premain rather than on application context load. It now weaves all the classes and in reasonable time.

However, I'd prefer not to go down this hacky road as I can only presume that the two agents were designed the way it is for a reason.

I wonder if anyone else has seen a similar issue with the aspectjweaver javaagent and if someone might know why that agent is so slow compared to just using spring-instrument.

Upvotes: 3

Views: 1547

Answers (1)

kennyg
kennyg

Reputation: 1059

If the answer interests anyone, I've figured out the issue.

Spring uses a temporary classloader ContextOverridingClassLoader to get metadata about the bean classes prior to actually loading them into the context.

The spring-instrument javaagent (or more accurately, the spring framework code which may or may not use the spring-instrument javaagent) specifically only weaves classes loaded by the classloader used to load the application context.

Code inside of InstrumentationLoadTimeWeaver$FilteringClassFileTransformer:

        if (!this.targetClassLoader.equals(loader)) {
            return null;
        }
        return this.targetTransformer.transform(
                loader, className, classBeingRedefined, protectionDomain, classfileBuffer);

On the other hand, aspectjweaver does not have such a filtering mechanism and so will weave even those classes loaded by spring's temporary ContextOverridingClassLoader. Fortunately, aspectjweaver has an essentially undocumented system property (or at least I was unable to find any documentation on this) called aj.weaving.loadersToSkip. By setting this to:

-Daj.weaving.loadersToSkip=org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader

I was able to skip weaving for that classloader and speed up the loading of my application context tremendously.

Incidentally, I've found that both the spring-instrument and aspectjweaver ultimately both use ClassPreProcessorAgentAdapter to weave the classes, and thus it is probably not necessary to use both agents (aspectjweaver will weave a superset of the classes that spring-instrument will). However, depending on your configuration, the application might complain about the missing agent at startup so you might as well include it (at the cost of some additional unnecessary overhead).

Upvotes: 4

Related Questions