Backend Development 12 min read

Java Agent Instrumentation for AOP Method Timing without Spring

This article explains how to implement Java Instrumentation using a custom Java agent to achieve AOP‑style method timing without Spring, covering Instrument concepts, Maven manifest configuration, Agent entry points, JDK Attach API loading, class file transformers, annotation processing, and integration with QTrace for full‑stack tracing.

Qunar Tech Salon
Qunar Tech Salon
Qunar Tech Salon
Java Agent Instrumentation for AOP Method Timing without Spring

The article is the second part of a two‑article series that introduces Java Instrumentation concepts (Instrument, Attach API, JVMTI, Agent, ASM) and demonstrates how to replace Spring AOP with a custom Java agent that measures method execution time.

It defines an AgentMain class with premain and agentmain methods to receive the Instrumentation instance, and provides a static instrumentation() method that returns this instance via reflection.

A Maven pom.xml snippet shows how to configure the MANIFEST.MF entries ( Premain-Class , Agent-Class , Can-Redefine-Classes , Can-Retransform-Classes ) so the agent can be loaded at runtime.

The JDKAgentLoader uses the Attach API (specifically VirtualMachine.attach ) to load the agent JAR into a running JVM, handling both HotSpot and non‑HotSpot VMs and providing helpful error messages for unsupported environments.

A MethodCostTimeFileTransformer implements ClassFileTransformer . It checks whether a class name is in a configured list, then uses ASM ClassReader and ClassWriter together with an AopClassVisitor (the same visitor used in phase 1) to inject timing code into the bytecode.

The Instruments class manages the agent lifecycle: it loads the agent via JDKAgentLoader , obtains the Instrumentation instance, and registers the transformer with inst.addTransformer(new MethodCostTimeFileTransformer(classPathList)) .

To avoid loading annotated classes before transformation, a compile‑time annotation processor ( CostAnnotationProcessor ) scans for the custom @Cost annotation, writes the fully‑qualified class names to a resource file ( cost_annotation ), and later the agent reads this file to know which classes to instrument.

The article also describes how QTrace (QuNar’s tracing framework) uses the same instrumentation mechanism. It shows the Maven modules involved ( qtracer‑instrument‑annotation , qtracer‑instrument‑asm , qtracer‑instrument‑annotation‑processor , qtracer‑instrument‑agent , etc.), the generated annotation file format, and the runtime flow where Instruments.start() loads the agent, adds a QTraceClassFileTransformer , and registers HTTP handlers for tracing requests.

Finally, the article outlines the core logic of TraceClassVisitor and TraceMethodVisitor , which wrap the original method body in a try‑catch‑finally block, start a QTrace scope, record arguments, handle exceptions, and close the scope, ensuring that even private or final methods can be instrumented.

JavaInstrumentationAOPbytecodemavenJava agentannotation-processingqtrace
Qunar Tech Salon
Written by

Qunar Tech Salon

Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.