Articles
Enterprise Architecture
JVM weaving is the natural answer to most of the issues discussed above. To understand why, we will look at a couple of examples that show the JVM is already doing most of the work necessary to do weaving: When a class gets loaded, the JVM does read the bytecode to build up the data needed to serve the
java.lang.reflect.* API purpose. Another example is method dispatching. Modern JVMs compile the bytecode of methods or code blocks to more advanced and efficient constructs and execution flows (doing code inlining where applicable). Due to the HotSwap API requirements, the JRockit JVM (and probably other JVMs too) also does bookkeeping on which method calls which other method, so that a method body can still be hotswapped in all expected places—inlined or not—if its defining class is redefined at runtime.
As a consequence, instead of changing the bytecode to weave in an advice invocation— say before a specific method call—the JVM could actually have knowledge about it and simply do a dispatch to the advice at any matching join point prior to dispatching to the actual method.
As bytecode would be untouched, immediate advantages can be expected, such as:
A detailed description of the proposed JRockit JVM support for AOP will be presented in the second article of this series.
The following code sample serves as the concluding illustration. It dispatches to the static method
advice() just before the
sayHello() method gets called :
public class Hello {
// -- the sample method to intercept
public void sayHello() {
System.out.println("Hello World");
}
// -- using the JRockit JVM support for AOP
static void weave() throws Throwable {
// match on method name
StringFilter methodName = new StringFilter(
"sayHello",
StringFilter.Type.EXACT
);
// match on callee type
ClassFilter klass = new ClassFilter(
Hello.class,
false,
null
);
// advice is a regular method dispatch
Method advice = Aspect.class.getDeclaredMethod(
"advice",
new Class[0]
);
// get a JRockit weaver and subscribe the
// advice to the join point picked out by the filter
Weaver w = WeaverFactory.createWeaver();
w.addSubscription(new MethodSubscription(
new MethodFilter(
0,
null,
klass,
methodName,
null,
null
),
MethodSubscription.InsertionType.BEFORE,
advice
));
}
// -- sample code
static void test() {
new Hello().sayHello();
}
public static void main(String a[])
throws Throwable {
weave();
test();
}
// -- the sample aspect
public static class Aspect {
public static void advice() {
System.out.println("About to say:");
}
}
}
Bytecode instrumentation has gained popularity in the Java community to implement advanced technologies such as AOP or transparent services addition in the middleware space. However, it suffers from several key limitations, and its widespread use will cause further issues affecting both scalability and usability.
Since bytecode instrumentation has more or less become the standard way of implementing weaving in AOP, it will suffer, if it hasn't already, from the limitations and problems outlined in this article.
We believe that JVM support for AOP is the natural solution to those problems. We are proposing a subscription-based API that we have implemented in the JRockit JVM, which is closely integrated with the JVM method dispatch internals. The next article in this series will illustrate in more detail the API, and explain how each problem is solved.
Jonas Bonér is a senior software engineer at the JRockit team at BEA Systems and is currently working on dynamic AOP, VM weaving and AOP evangelism. He is the founder of the AspectWerkz AOP framework and committer to the AspectJ 5 project.
Joakim Dahlstedt is the CTO of the Java Runtime Products Group at BEA Systems, Inc., where he is responsible for the future development directions for the JVM.
Alexandre Vasseur works as a software engineer at BEA Systems within the Java Runtime Product Group, focusing on Aspect Oriented Technology. He is the co-founder of the AspectWerkz AOP framework and committer on Eclipse AspectJ 5.