LoadTimeWeaver.getThrowawayClassLoader() decorated for exclude support (if necessary)

Issue: SPR-13886
This commit is contained in:
Juergen Hoeller 2016-04-11 19:19:37 +02:00
parent 448621ac58
commit b82df144e4
8 changed files with 97 additions and 62 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2016 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.
@ -22,6 +22,8 @@ import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.DecoratingClassLoader;
import org.springframework.core.OverridingClassLoader;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@ -97,15 +99,14 @@ public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver {
Assert.notNull(classLoader, "ClassLoader must not be null");
this.classLoader = classLoader;
this.addTransformerMethod = ClassUtils.getMethodIfAvailable(
this.classLoader.getClass(), ADD_TRANSFORMER_METHOD_NAME,
new Class<?>[] {ClassFileTransformer.class});
this.classLoader.getClass(), ADD_TRANSFORMER_METHOD_NAME, ClassFileTransformer.class);
if (this.addTransformerMethod == null) {
throw new IllegalStateException(
"ClassLoader [" + classLoader.getClass().getName() + "] does NOT provide an " +
"'addTransformer(ClassFileTransformer)' method.");
}
this.getThrowawayClassLoaderMethod = ClassUtils.getMethodIfAvailable(
this.classLoader.getClass(), GET_THROWAWAY_CLASS_LOADER_METHOD_NAME, new Class<?>[0]);
this.classLoader.getClass(), GET_THROWAWAY_CLASS_LOADER_METHOD_NAME);
// getThrowawayClassLoader method is optional
if (this.getThrowawayClassLoaderMethod == null) {
if (logger.isInfoEnabled()) {
@ -130,7 +131,10 @@ public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver {
@Override
public ClassLoader getThrowawayClassLoader() {
if (this.getThrowawayClassLoaderMethod != null) {
return (ClassLoader) ReflectionUtils.invokeMethod(this.getThrowawayClassLoaderMethod, this.classLoader);
ClassLoader target = (ClassLoader)
ReflectionUtils.invokeMethod(this.getThrowawayClassLoaderMethod, this.classLoader);
return (target instanceof DecoratingClassLoader ? target :
new OverridingClassLoader(this.classLoader, target));
}
else {
return new SimpleThrowawayClassLoader(this.classLoader);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2016 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.
@ -20,6 +20,7 @@ import java.lang.instrument.ClassFileTransformer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.core.OverridingClassLoader;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@ -109,7 +110,7 @@ public class GlassFishLoadTimeWeaver implements LoadTimeWeaver {
@Override
public ClassLoader getThrowawayClassLoader() {
try {
return (ClassLoader) this.copyMethod.invoke(this.classLoader);
return new OverridingClassLoader(this.classLoader, (ClassLoader) this.copyMethod.invoke(this.classLoader));
}
catch (InvocationTargetException ex) {
throw new IllegalStateException("GlassFish copy method threw exception", ex.getCause());

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2016 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.
@ -20,6 +20,7 @@ import java.lang.instrument.ClassFileTransformer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.core.OverridingClassLoader;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@ -103,7 +104,7 @@ public class TomcatLoadTimeWeaver implements LoadTimeWeaver {
@Override
public ClassLoader getThrowawayClassLoader() {
try {
return (ClassLoader) this.copyMethod.invoke(this.classLoader);
return new OverridingClassLoader(this.classLoader, (ClassLoader) this.copyMethod.invoke(this.classLoader));
}
catch (InvocationTargetException ex) {
throw new IllegalStateException("Tomcat copy method threw exception", ex.getCause());

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 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.
@ -18,6 +18,7 @@ package org.springframework.instrument.classloading.weblogic;
import java.lang.instrument.ClassFileTransformer;
import org.springframework.core.OverridingClassLoader;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@ -70,6 +71,8 @@ public class WebLogicLoadTimeWeaver implements LoadTimeWeaver {
@Override
public ClassLoader getThrowawayClassLoader() {
return this.classLoader.getThrowawayClassLoader();
return new OverridingClassLoader(this.classLoader.getClassLoader(),
this.classLoader.getThrowawayClassLoader());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 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.
@ -29,47 +29,57 @@ import org.springframework.util.Assert;
/**
*
* Reflective wrapper around a WebSphere 7 class loader. Used to
* Reflective wrapper around a WebSphere 7+ class loader. Used to
* encapsulate the classloader-specific methods (discovered and
* called through reflection) from the load-time weaver.
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 3.1
*/
class WebSphereClassLoaderAdapter {
private static final String COMPOUND_CLASS_LOADER_NAME = "com.ibm.ws.classloader.CompoundClassLoader";
private static final String CLASS_PRE_PROCESSOR_NAME = "com.ibm.websphere.classloader.ClassLoaderInstancePreDefinePlugin";
private static final String PLUGINS_FIELD = "preDefinePlugins";
private ClassLoader classLoader;
private Class<?> wsPreProcessorClass;
private Method addPreDefinePlugin;
private Constructor<? extends ClassLoader> cloneConstructor;
private Field transformerList;
public WebSphereClassLoaderAdapter(ClassLoader classLoader) {
Class<?> wsCompoundClassLoaderClass = null;
Class<?> wsCompoundClassLoaderClass;
try {
wsCompoundClassLoaderClass = classLoader.loadClass(COMPOUND_CLASS_LOADER_NAME);
cloneConstructor = classLoader.getClass().getDeclaredConstructor(wsCompoundClassLoaderClass);
cloneConstructor.setAccessible(true);
this.cloneConstructor = classLoader.getClass().getDeclaredConstructor(wsCompoundClassLoaderClass);
this.cloneConstructor.setAccessible(true);
wsPreProcessorClass = classLoader.loadClass(CLASS_PRE_PROCESSOR_NAME);
addPreDefinePlugin = classLoader.getClass().getMethod("addPreDefinePlugin", wsPreProcessorClass);
transformerList = wsCompoundClassLoaderClass.getDeclaredField(PLUGINS_FIELD);
transformerList.setAccessible(true);
this.wsPreProcessorClass = classLoader.loadClass(CLASS_PRE_PROCESSOR_NAME);
this.addPreDefinePlugin = classLoader.getClass().getMethod("addPreDefinePlugin", this.wsPreProcessorClass);
this.transformerList = wsCompoundClassLoaderClass.getDeclaredField(PLUGINS_FIELD);
this.transformerList.setAccessible(true);
}
catch (Exception ex) {
throw new IllegalStateException(
"Could not initialize WebSphere LoadTimeWeaver because WebSphere 7 API classes are not available",
ex);
"Could not initialize WebSphere LoadTimeWeaver because WebSphere API classes are not available", ex);
}
if (!wsCompoundClassLoaderClass.isInstance(classLoader)) {
throw new IllegalArgumentException("ClassLoader must be instance of [" + COMPOUND_CLASS_LOADER_NAME + "]");
}
Assert.isInstanceOf(wsCompoundClassLoaderClass, classLoader,
"ClassLoader must be instance of [" + COMPOUND_CLASS_LOADER_NAME + "]");
this.classLoader = classLoader;
}
public ClassLoader getClassLoader() {
return this.classLoader;
}
@ -79,9 +89,8 @@ class WebSphereClassLoaderAdapter {
try {
InvocationHandler adapter = new WebSphereClassPreDefinePlugin(transformer);
Object adapterInstance = Proxy.newProxyInstance(this.wsPreProcessorClass.getClassLoader(),
new Class<?>[] { this.wsPreProcessorClass }, adapter);
new Class<?>[] {this.wsPreProcessorClass}, adapter);
this.addPreDefinePlugin.invoke(this.classLoader, adapterInstance);
}
catch (InvocationTargetException ex) {
throw new IllegalStateException("WebSphere addPreDefinePlugin method threw exception", ex.getCause());
@ -93,9 +102,9 @@ class WebSphereClassLoaderAdapter {
public ClassLoader getThrowawayClassLoader() {
try {
ClassLoader loader = cloneConstructor.newInstance(getClassLoader());
// clear out the transformers (copied as well)
List<?> list = (List<?>) transformerList.get(loader);
ClassLoader loader = this.cloneConstructor.newInstance(getClassLoader());
// Clear out the transformers (copied as well)
List<?> list = (List<?>) this.transformerList.get(loader);
list.clear();
return loader;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2016 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.
@ -18,6 +18,7 @@ package org.springframework.instrument.classloading.websphere;
import java.lang.instrument.ClassFileTransformer;
import org.springframework.core.OverridingClassLoader;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@ -67,7 +68,8 @@ public class WebSphereLoadTimeWeaver implements LoadTimeWeaver {
@Override
public ClassLoader getThrowawayClassLoader() {
return this.classLoader.getThrowawayClassLoader();
return new OverridingClassLoader(this.classLoader.getClassLoader(),
this.classLoader.getThrowawayClassLoader());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 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.
@ -16,8 +16,9 @@
package org.springframework.core;
import java.util.HashSet;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.lang.UsesJava7;
import org.springframework.util.Assert;
@ -49,11 +50,11 @@ public abstract class DecoratingClassLoader extends ClassLoader {
}
private final Set<String> excludedPackages = new HashSet<String>();
private final Set<String> excludedPackages =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(8));
private final Set<String> excludedClasses = new HashSet<String>();
private final Object exclusionMonitor = new Object();
private final Set<String> excludedClasses =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(8));
/**
@ -79,10 +80,8 @@ public abstract class DecoratingClassLoader extends ClassLoader {
*/
public void excludePackage(String packageName) {
Assert.notNull(packageName, "Package name must not be null");
synchronized (this.exclusionMonitor) {
this.excludedPackages.add(packageName);
}
}
/**
* Add a class name to exclude from decoration (e.g. overriding).
@ -92,10 +91,8 @@ public abstract class DecoratingClassLoader extends ClassLoader {
*/
public void excludeClass(String className) {
Assert.notNull(className, "Class name must not be null");
synchronized (this.exclusionMonitor) {
this.excludedClasses.add(className);
}
}
/**
* Determine whether the specified class is excluded from decoration
@ -107,7 +104,6 @@ public abstract class DecoratingClassLoader extends ClassLoader {
* @see #excludeClass
*/
protected boolean isExcluded(String className) {
synchronized (this.exclusionMonitor) {
if (this.excludedClasses.contains(className)) {
return true;
}
@ -116,7 +112,6 @@ public abstract class DecoratingClassLoader extends ClassLoader {
return true;
}
}
}
return false;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 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.
@ -38,7 +38,8 @@ import org.springframework.util.FileCopyUtils;
public class OverridingClassLoader extends DecoratingClassLoader {
/** Packages that are excluded by default */
public static final String[] DEFAULT_EXCLUDED_PACKAGES = new String[] {"java.", "javax.", "sun.", "oracle."};
public static final String[] DEFAULT_EXCLUDED_PACKAGES = new String[]
{"java.", "javax.", "sun.", "oracle.", "javassist.", "org.springframework.core."};
private static final String CLASS_FILE_SUFFIX = ".class";
@ -49,12 +50,26 @@ public class OverridingClassLoader extends DecoratingClassLoader {
}
private final ClassLoader overrideDelegate;
/**
* Create a new OverridingClassLoader for the given ClassLoader.
* @param parent the ClassLoader to build an overriding ClassLoader for
*/
public OverridingClassLoader(ClassLoader parent) {
this(parent, null);
}
/**
* Create a new OverridingClassLoader for the given ClassLoader.
* @param parent the ClassLoader to build an overriding ClassLoader for
* @param overrideDelegate the ClassLoader to delegate to for overriding
* @since 4.3
*/
public OverridingClassLoader(ClassLoader parent, ClassLoader overrideDelegate) {
super(parent);
this.overrideDelegate = overrideDelegate;
for (String packageName : DEFAULT_EXCLUDED_PACKAGES) {
excludePackage(packageName);
}
@ -62,20 +77,25 @@ public class OverridingClassLoader extends DecoratingClassLoader {
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> result = null;
if (isEligibleForOverriding(name)) {
result = loadClassForOverriding(name);
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (this.overrideDelegate != null && isEligibleForOverriding(name)) {
return this.overrideDelegate.loadClass(name);
}
return super.loadClass(name);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (isEligibleForOverriding(name)) {
Class<?> result = loadClassForOverriding(name);
if (result != null) {
if (resolve) {
resolveClass(result);
}
return result;
}
else {
return super.loadClass(name, resolve);
}
return super.loadClass(name, resolve);
}
/**