3

I am trying to enable AspectJ load-time weaving (not Spring AOP) in a Spring Boot application. My goal is to weave advice into annotated fields and java.lang.reflect.Field.set(Object, Object) at load-time.

Per the Spring docs, I tried:

@Configuration
@EnableLoadTimeWeaving
public class Config {}

Running the Spring Boot application with this configuration resulted in the application context failing to load with this message:

Caused by: java.lang.IllegalStateException:
  ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader]
    does NOT provide an 'addTransformer(ClassFileTransformer)' method.
    Specify a custom LoadTimeWeaver or start your Java virtual machine
    with Spring's agent: -javaagent:spring-instrument-{version}.jar

The latter suggestion in that message is not a good option as I am trying to avoid necessitating launch script modifications. The aspect I need to weave actually resides in a library, so all implementing Spring Boot projects will have to make whatever changes required to get LTW to work.

I also tried this configuration:

@Configuration
@EnableLoadTimeWeaving
public class Config implements LoadTimeWeavingConfigurer {

    @Override
    public LoadTimeWeaver getLoadTimeWeaver() {
        return new ReflectiveLoadTimeWeaver();
    }
}

Running the Spring Boot application with this configuration resulted in the application context failing to load with this message:

Caused by: java.lang.IllegalStateException:
  ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader]
    does NOT provide an 'addTransformer(ClassFileTransformer)' method.

It seems I need to make the JVM use a class loader that has an addTransformer(ClassFileTransformer) method. I don't know how to do that, particularly for this situation. Any suggestions?

kriegaex
  • 63,017
  • 15
  • 111
  • 202
Aaron B
  • 53
  • 3
  • 1
    I wonder why so many people refuse to modify launch scripts and would rather change compiled code for a thing as simple as activating a Java agent. Hot-attaching an agent is possible, but so much more invasive. Furthermore, the agent hot-attached thus can only instrument classes which are loaded _after_ the agent was attached, which makes such a setup sort of brittle. Does that make any sense? – kriegaex Feb 04 '22 at 02:47
  • Yes, that makes perfect sense. I didn't realize that hot-attaching an agent, as it is called, would be more invasive and brittle than specifying the agent in the launch script. Thank you for your clarification, kriegaex. – Aaron B Feb 04 '22 at 13:54
  • Thanks for reacting to my general comment. What about my actual answer to your question? Did you at least verify if it works for you. You neither a accepted nor commented on it. Thanks in advance. – kriegaex Feb 05 '22 at 00:24
  • My apologies. I needed some time to go over your answer. This is for a work project, so I was not working on it over the weekend. – Aaron B Feb 07 '22 at 17:51

1 Answers1

2

I am not an active Spring user, but I know that Spring supports annotation- or XML-configured agent hot-attachment and has some container-specific classes for that according to its documentation. It does not seem to work reliably in all situations, though, especially when running a Spring Boot application from an IDE or so.

Anyway, the AspectJ weaver 1.8.7 and more recent can be hot-attached. I explained how to do that in a Spring setup here. If you want a simpler solution with less boilerplate but one more dependency to a tiny helper library called byte-buddy-agent, you can use this solution as a shortcut. I have not tried it, but I know the helper library and am using it myself in other contexts when hot-attaching bytecode instrumentation agents, avoiding the fuss to cater to different JVM versions and configuration situations. But in order for that to work on JVM 9+, you might need to manually activate auto-attachment for the JVM, which would be another modification for your start-up script, and you would be back to square 1.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Thank you for your answer. I agree with your comment on my post that activating a Java agent via launch scripts is preferable over agent hot-attachment. I have not yet pursued hot-attaching an agent, so I do not know if it would for me. However, I have gone a different direction. Instead of doing LTW, I have found that post-compile weaving will work for most use cases. For edge cases, users can implement LTW by specifying the Java agent via launch scripts. Thank you again for your help. You have pushed me toward a better solution. – Aaron B Feb 07 '22 at 18:04