How to use load time weaving without -javaagent?

859 views Asked by At

I am trying to enable loadtimeweaving without javaagent jar files of aspectweaver and spring-instrument. This what I have implemented to achieve the same But it's not working.

@ComponentScan("com.myapplication")
@EnableAspectJAutoProxy
@EnableSpringConfigured
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.AUTODETECT)
public class AopConfig implements LoadTimeWeavingConfigurer {
 
 @Override
 public LoadTimeWeaver getLoadTimeWeaver() {
     return new ReflectiveLoadTimeWeaver();
 }
 
  /**
  * Makes the aspect a Spring bean, eligible for receiving autowired components.
  */
 @Bean
 public InstrumentationLoadTimeWeaver loadTimeWeaver()  throws Throwable {
     InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
     return loadTimeWeaver;
 }

}
1

There are 1 answers

0
kriegaex On

A workaround I found was to hot-attach InstrumentationSavingAgent from spring-instrument instead of starting the agent via -javaagent command line parameter. But for that you need an Instrumentation instance. I just used the tiny helper library byte-buddy-helper (works independently of ByteBuddy, don't worry) which can do just that. Make sure that in Java 9+ JVMs the Attach API is activated if for some reason this is not working.

So get rid of implements LoadTimeWeavingConfigurer and the two factory methods in your configuration class and just do it like this:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-instrument</artifactId>
</dependency>
<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy-agent</artifactId>
    <version>1.10.14</version>
</dependency>
@SpringBootApplication
public class Application {
  public static void main(String[] args) {
    Instrumentation instrumentation = ByteBuddyAgent.install();
    InstrumentationSavingAgent.premain("", instrumentation);
    ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
    // ...
  }
}

Feel free to ask follow-up questions if there is anything you do not understand.


Update: One more thing I noticed is that this only works for me with aspectjWeaving = ENABLED, not with AUTODETECT. And for one sample Spring bean I noticed that @Component did not work, probably because of some bootstrapping issue between Spring vs AspectJ. Hence, I replaced it by an explicit @Bean configuration, then it worked. Something like this:

@Configuration
@ComponentScan("com.spring.aspect.dynamicflow")
@EnableLoadTimeWeaving(aspectjWeaving = ENABLED)
public class ApplicationConfig {
  @Bean
  public JobProcess jobProcess() {
    return new JobProcessImpl();
  }
}

Update 2024-03-19: If you are running your applications as executable JARs on JRE 9+ (Spring Boot ones or other types), probably Agent Embedder Maven Plugin is what you want.

It enables you to embed a java agent in your executable JAR and have it started automatically using the Launcher-Agent-Class JVM mechanism.

Unique features added by this plugin and unavailable via the original JVM mechanism: You can

  • embed and run multiple agents (the JVM supports only one out of the box),
  • pass an option string to each agent, just like from the JVM command line.

Spoiler: I am the author of the plugin and also happen to be the current maintainer of AspectJ.

P.S.: In the case of the AspectJ weaver, as the JVM starts the agent very early, weaving will be active without extra Spring configuration and it should work for all classloaders - no more ClassLoader [...] does NOT provide an 'addTransformer(ClassFileTransformer)' method errors as seen when hot-attaching the weaver via spring-instrument.jar.