Search code examples
springspring-bootclassloaderaspectjload-time-weaving

EnableLoadTimeWeaving annotation causes application context to fail to load


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?


Solution

  • 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.