001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core; 018 019import java.io.IOException; 020import java.io.InputStream; 021 022import org.springframework.lang.UsesJava7; 023import org.springframework.util.FileCopyUtils; 024 025/** 026 * {@code ClassLoader} that does <i>not</i> always delegate to the parent loader 027 * as normal class loaders do. This enables, for example, instrumentation to be 028 * forced in the overriding ClassLoader, or a "throwaway" class loading behavior 029 * where selected application classes are temporarily loaded in the overriding 030 * {@code ClassLoader} for introspection purposes before eventually loading an 031 * instrumented version of the class in the given parent {@code ClassLoader}. 032 * 033 * @author Rod Johnson 034 * @author Juergen Hoeller 035 * @since 2.0.1 036 */ 037@UsesJava7 038public class OverridingClassLoader extends DecoratingClassLoader { 039 040 /** Packages that are excluded by default */ 041 public static final String[] DEFAULT_EXCLUDED_PACKAGES = new String[] 042 {"java.", "javax.", "sun.", "oracle.", "javassist.", "org.aspectj.", "net.sf.cglib."}; 043 044 private static final String CLASS_FILE_SUFFIX = ".class"; 045 046 static { 047 if (parallelCapableClassLoaderAvailable) { 048 ClassLoader.registerAsParallelCapable(); 049 } 050 } 051 052 053 private final ClassLoader overrideDelegate; 054 055 056 /** 057 * Create a new OverridingClassLoader for the given ClassLoader. 058 * @param parent the ClassLoader to build an overriding ClassLoader for 059 */ 060 public OverridingClassLoader(ClassLoader parent) { 061 this(parent, null); 062 } 063 064 /** 065 * Create a new OverridingClassLoader for the given ClassLoader. 066 * @param parent the ClassLoader to build an overriding ClassLoader for 067 * @param overrideDelegate the ClassLoader to delegate to for overriding 068 * @since 4.3 069 */ 070 public OverridingClassLoader(ClassLoader parent, ClassLoader overrideDelegate) { 071 super(parent); 072 this.overrideDelegate = overrideDelegate; 073 for (String packageName : DEFAULT_EXCLUDED_PACKAGES) { 074 excludePackage(packageName); 075 } 076 } 077 078 079 @Override 080 public Class<?> loadClass(String name) throws ClassNotFoundException { 081 if (this.overrideDelegate != null && isEligibleForOverriding(name)) { 082 return this.overrideDelegate.loadClass(name); 083 } 084 return super.loadClass(name); 085 } 086 087 @Override 088 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 089 if (isEligibleForOverriding(name)) { 090 Class<?> result = loadClassForOverriding(name); 091 if (result != null) { 092 if (resolve) { 093 resolveClass(result); 094 } 095 return result; 096 } 097 } 098 return super.loadClass(name, resolve); 099 } 100 101 /** 102 * Determine whether the specified class is eligible for overriding 103 * by this class loader. 104 * @param className the class name to check 105 * @return whether the specified class is eligible 106 * @see #isExcluded 107 */ 108 protected boolean isEligibleForOverriding(String className) { 109 return !isExcluded(className); 110 } 111 112 /** 113 * Load the specified class for overriding purposes in this ClassLoader. 114 * <p>The default implementation delegates to {@link #findLoadedClass}, 115 * {@link #loadBytesForClass} and {@link #defineClass}. 116 * @param name the name of the class 117 * @return the Class object, or {@code null} if no class defined for that name 118 * @throws ClassNotFoundException if the class for the given name couldn't be loaded 119 */ 120 protected Class<?> loadClassForOverriding(String name) throws ClassNotFoundException { 121 Class<?> result = findLoadedClass(name); 122 if (result == null) { 123 byte[] bytes = loadBytesForClass(name); 124 if (bytes != null) { 125 result = defineClass(name, bytes, 0, bytes.length); 126 } 127 } 128 return result; 129 } 130 131 /** 132 * Load the defining bytes for the given class, 133 * to be turned into a Class object through a {@link #defineClass} call. 134 * <p>The default implementation delegates to {@link #openStreamForClass} 135 * and {@link #transformIfNecessary}. 136 * @param name the name of the class 137 * @return the byte content (with transformers already applied), 138 * or {@code null} if no class defined for that name 139 * @throws ClassNotFoundException if the class for the given name couldn't be loaded 140 */ 141 protected byte[] loadBytesForClass(String name) throws ClassNotFoundException { 142 InputStream is = openStreamForClass(name); 143 if (is == null) { 144 return null; 145 } 146 try { 147 // Load the raw bytes. 148 byte[] bytes = FileCopyUtils.copyToByteArray(is); 149 // Transform if necessary and use the potentially transformed bytes. 150 return transformIfNecessary(name, bytes); 151 } 152 catch (IOException ex) { 153 throw new ClassNotFoundException("Cannot load resource for class [" + name + "]", ex); 154 } 155 } 156 157 /** 158 * Open an InputStream for the specified class. 159 * <p>The default implementation loads a standard class file through 160 * the parent ClassLoader's {@code getResourceAsStream} method. 161 * @param name the name of the class 162 * @return the InputStream containing the byte code for the specified class 163 */ 164 protected InputStream openStreamForClass(String name) { 165 String internalName = name.replace('.', '/') + CLASS_FILE_SUFFIX; 166 return getParent().getResourceAsStream(internalName); 167 } 168 169 170 /** 171 * Transformation hook to be implemented by subclasses. 172 * <p>The default implementation simply returns the given bytes as-is. 173 * @param name the fully-qualified name of the class being transformed 174 * @param bytes the raw bytes of the class 175 * @return the transformed bytes (never {@code null}; 176 * same as the input bytes if the transformation produced no changes) 177 */ 178 protected byte[] transformIfNecessary(String name, byte[] bytes) { 179 return bytes; 180 } 181 182}