All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver Maven / Gradle / Ivy

/*
 * Copyright 2002-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.instrument.classloading;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;

import org.springframework.instrument.InstrumentationSavingAgent;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
 * {@link LoadTimeWeaver} relying on VM {@link Instrumentation}.
 *
 * 

Start the JVM specifying the Java agent to be used, like as follows: * *

-javaagent:path/to/org.springframework.instrument.jar * *

where {@code org.springframework.instrument.jar} is a JAR file containing * the {@link InstrumentationSavingAgent} class, as shipped with Spring. * *

In Eclipse, for example, set the "Run configuration"'s JVM args to be of the form: * *

-javaagent:${project_loc}/lib/org.springframework.instrument.jar * * @author Rod Johnson * @author Juergen Hoeller * @since 2.0 * @see InstrumentationSavingAgent */ public class InstrumentationLoadTimeWeaver implements LoadTimeWeaver { private static final boolean AGENT_CLASS_PRESENT = ClassUtils.isPresent( "org.springframework.instrument.InstrumentationSavingAgent", InstrumentationLoadTimeWeaver.class.getClassLoader()); private final ClassLoader classLoader; private final Instrumentation instrumentation; private final List transformers = new ArrayList(4); /** * Create a new InstrumentationLoadTimeWeaver for the default ClassLoader. */ public InstrumentationLoadTimeWeaver() { this(ClassUtils.getDefaultClassLoader()); } /** * Create a new InstrumentationLoadTimeWeaver for the given ClassLoader. * @param classLoader the ClassLoader that registered transformers are supposed to apply to */ public InstrumentationLoadTimeWeaver(ClassLoader classLoader) { Assert.notNull(classLoader, "ClassLoader must not be null"); this.classLoader = classLoader; this.instrumentation = getInstrumentation(); } @Override public void addTransformer(ClassFileTransformer transformer) { Assert.notNull(transformer, "Transformer must not be null"); FilteringClassFileTransformer actualTransformer = new FilteringClassFileTransformer(transformer, this.classLoader); synchronized (this.transformers) { if (this.instrumentation == null) { throw new IllegalStateException( "Must start with Java agent to use InstrumentationLoadTimeWeaver. See Spring documentation."); } this.instrumentation.addTransformer(actualTransformer); this.transformers.add(actualTransformer); } } /** * We have the ability to weave the current class loader when starting the * JVM in this way, so the instrumentable class loader will always be the * current loader. */ @Override public ClassLoader getInstrumentableClassLoader() { return this.classLoader; } /** * This implementation always returns a {@link SimpleThrowawayClassLoader}. */ @Override public ClassLoader getThrowawayClassLoader() { return new SimpleThrowawayClassLoader(getInstrumentableClassLoader()); } /** * Remove all registered transformers, in inverse order of registration. */ public void removeTransformers() { synchronized (this.transformers) { if (!this.transformers.isEmpty()) { for (int i = this.transformers.size() - 1; i >= 0; i--) { this.instrumentation.removeTransformer(this.transformers.get(i)); } this.transformers.clear(); } } } /** * Check whether an Instrumentation instance is available for the current VM. * @see #getInstrumentation() */ public static boolean isInstrumentationAvailable() { return (getInstrumentation() != null); } /** * Obtain the Instrumentation instance for the current VM, if available. * @return the Instrumentation instance, or {@code null} if none found * @see #isInstrumentationAvailable() */ private static Instrumentation getInstrumentation() { if (AGENT_CLASS_PRESENT) { return InstrumentationAccessor.getInstrumentation(); } else { return null; } } /** * Inner class to avoid InstrumentationSavingAgent dependency. */ private static class InstrumentationAccessor { public static Instrumentation getInstrumentation() { return InstrumentationSavingAgent.getInstrumentation(); } } /** * Decorator that only applies the given target transformer to a specific ClassLoader. */ private static class FilteringClassFileTransformer implements ClassFileTransformer { private final ClassFileTransformer targetTransformer; private final ClassLoader targetClassLoader; public FilteringClassFileTransformer(ClassFileTransformer targetTransformer, ClassLoader targetClassLoader) { this.targetTransformer = targetTransformer; this.targetClassLoader = targetClassLoader; } @Override public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (!this.targetClassLoader.equals(loader)) { return null; } return this.targetTransformer.transform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer); } @Override public String toString() { return "FilteringClassFileTransformer for: " + this.targetTransformer.toString(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy