6.2 Load-time Weaving

New Feature in Spring 2.5

Spring 2.5 has added support to make it easier to use AspectJ Load-time Weaving (LTW). Spring LTW also has finer grained control and can activate load-time weaving on a per classloader basis. Per classloader load-time weaving can easily be activated on standard applications, Servlet Containers like Tomcat, and also some Java EE application servers.

AspectJ has had load-time weaving (LTW) support for some time. Load-time weaving let's AspectJ apply advice to classes on the fly as they are loaded by the classloader. This can be enabled by using the '-javaagent' JVM argument added in Java 5. It allows you to register a class that will give you access to java.lang.instrument.Instrumentation which can be used to register class transformers that can modify byte code as classes are loaded. This is meant to be used for adding byte code for monitoring tools, tracing, etc. The jar passed into the '-javaagent' only needs to be a Premain-Class entry in the jar's manifest which specifies the instrumentation class that has a public static void premain(String agentArgs, Instrumentation inst) defined in it to accept the Instrumentation implementation. For example, the AspectJ LTW can be registered by running 'java -javaagent:c:/aspectj/aspectjweaver.jar MyProgram'. This enables AspectJ LTW for any class loaded by the application. More information on AspectJ LTW can be found at http://www.eclipse.org/aspectj/doc/released/devguide/ltw-configuration.html.

Spring's LTW support includes it's own java agent that can be started by running an application by passing in the spring-agent.jar (ex: 'java -javaagent:c:/spring-framework-2.5/dist/weaving/spring-agent.jar MyProgram'). When the java agent has been registered, context:load-time-weaver can be used to add a load-time weaver to the current classloader. Once this is done, it's pure AspectJ LTW which can be configured using 'META-INF/aop.xml' which is automatically loaded as AspectJ LTW is initialized by context:load-time-weaver.

If the context:load-time-weaver element's weaving-class attribute isn't specified explicitly, DefaultContextLoadTimeWeaver will be used to autodetect the appropriate implementation to use to properly register the AspectJ LTW with the classloader. The table below show's all of the different load-time weaver implemenation and how they are selected. Whatever load-time weaver implementation is used will be exposed as a loadTimeWeaver bean. This can be used to register other java.lang.instrument.ClassFileTransformer implementations if needed. The AspectJ load-time weaver implementation of ClassFileTransformer that was registered is org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.

Table 6.5. Classloaders Auto-detected by Context Load-time Weaver

Supported LTW IntegrationLTW ImplementationDescription
Sun's GlassFishGlassFishLoadTimeWeaver Checks if the classloader's class name starts with com.sun.enterprise.
Oracle's OC4JOC4JLoadTimeWeaver Checks if the classloader's class name starts with 'oracle'. Must be using OC4J 10.1.3.1 or higher.
BEA's WebLogicWebLogicLoadTimeWeaver Checks if the classloader's class name starts with weblogic.
Spring AgentInstrumentationLoadTimeWeaver If the classloader wasn't GlassFish, OC4J, or WebLogic, then the org.springframework.instrument.InstrumentationSavingAgent is checked to see if an java.lang.instrument.Instrumentation was set on it by the Spring Agent.
OtherReflectiveLoadTimeWeaver If none of the other checks were valid, a org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver implementation is used.

Another feature of context:load-time-weaver is setting whether it should do load-time weaving. This can be controlled by setting the aspjectj-weaving attribute. It can be set to 'on', 'off', and 'autodetect' (which is the default). In autodetect mode, if at least one 'META-INF/aop.xml' file is found load-time weaving will be on.

[Note]Tomcat LTW Configuration

Make sure to have copied spring-tomcat-weaver.jar to Tomcat's lib directory so the TomcatInstrumentableClassLoader is available when Tomcat uses it for the context.

Example 6.1. Load-time Weaving

This shows using load-time weaving to log performance statistics. The context:load-time-weaver registers an AspectJ load-time weaver on the classloader. It also automatically loads and configures the 'META-INF/aop.xml' file in the classpath, and configures what classes advice should be applied to and all the aspects providing pointcuts and advice. The statistics are taken using Spring's StopWatch utility.

chapter06-aspectj-load-time-weaving/src/main/java/org/springbyexample/springindepth/chapter06/aspectjLoadTimeWeaving/PerformanceAdvice.java
                    
@Aspect
public class PerformanceAdvice {

    @Pointcut("execution(public * org.springbyexample.springindepth.chapter06.aspectjLoadTimeWeaving..*.*(..))")
    public void aspectjLoadTimeWeavingExamples() {
    }

    @Around("aspectjLoadTimeWeavingExamples()")
    public Object profile(ProceedingJoinPoint pjp) throws Throwable {
        final Logger logger = LoggerFactory.getLogger(pjp.getSignature().getDeclaringType());

        StopWatch sw = new StopWatch(getClass().getSimpleName());

        try {
            sw.start(pjp.getSignature().getName());

            return pjp.proceed();
        } finally {
            sw.stop();

            logger.debug(sw.prettyPrint());
        }
    }

}
                    
                
chapter06-aspectj-load-time-weaving/src/main/resources/META-INF/aop.xml
                    
<!DOCTYPE aspectj PUBLIC
        "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
    <weaver>
        <!-- only weave classes in this package -->
        <include within="org.springbyexample.springindepth.chapter06.aspectjLoadTimeWeaving.*" />
    </weaver>
    <aspects>
        <!-- use only this aspect for weaving -->
        <aspect name="org.springbyexample.springindepth.chapter06.aspectjLoadTimeWeaving.PerformanceAdvice" />
    </aspects>
</aspectj>
                    
                
chapter06-aspectj-load-time-weaving/src/main/resources/applicationContext.xml
                    
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
                                                http://www.springframework.org/schema/beans/spring-beans.xsd
                                                http://www.springframework.org/schema/context
                                                http://www.springframework.org/schema/context/spring-context.xsd">

    <context:load-time-weaver />
    
    <bean id="processor" class="org.springbyexample.springindepth.chapter06.aspectjLoadTimeWeaving.Processor" />
    
</beans>