spring-instrument.tomcat解析之一:Tomcat默许类加载器的扩展
spring-instrument.tomcat解析之一:Tomcat默认类加载器的扩展
1、在开始之前,建议先阅读这篇文章http://xj84.iteye.com/blog/1221105(利用ClassFileTransformer实现aop)
2、TomcatInstrumentableClassLoader:Tomcat默认类加载器的扩展,添加了instrumentation
3、WeavingTransformer:基于ClassFileTransformer的编织者,允许一系列转换者(transformer)织入到类字节码中。
把目标比作衣服,transformer就是衣服上的装饰,而WeavingTransformer就是缝纫机
1、在开始之前,建议先阅读这篇文章http://xj84.iteye.com/blog/1221105(利用ClassFileTransformer实现aop)
2、TomcatInstrumentableClassLoader:Tomcat默认类加载器的扩展,添加了instrumentation
package org.springframework.instrument.classloading.tomcat; import java.lang.instrument.ClassFileTransformer; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.apache.catalina.loader.ResourceEntry; import org.apache.catalina.loader.WebappClassLoader; import org.springframework.instrument.classloading.WeavingTransformer; /** * [Extension of Tomcat's default class loader] 【which】 [adds] [instrumentation] * [to loaded] [classes] (without the need to use a VM-wide agent). * Tomcat默认类加载器的扩展,添加了instrumentation,在不使用VM级别的代理情况下就加载类 *可以在tomcat的server.xml问中配置,代替默认的类加载器 * <p>To be registered using a * <code><a href="http://tomcat.apache.org/tomcat-5.5-doc/config/loader.html">Loader</a></code> tag * in Tomcat's <code><a href="http://tomcat.apache.org/tomcat-5.5-doc/config/context.html">Context</a></code> * definition in the <code>server.xml</code> file, with the Spring-provided * "spring-tomcat-weaver.jar" file deployed into Tomcat's "server/lib" (for Tomcat 5.x) or "lib" (for Tomcat 6.x) directory. * The required configuration tag looks as follows: * * <pre class="code"><Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/></pre> * * <p>Typically used in combination with a * {@link org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver} * defined in the Spring application context. The <code>addTransformer</code> and * <code>getThrowawayClassLoader</code> methods mirror the corresponding methods * in the LoadTimeWeaver interface, as expected by ReflectiveLoadTimeWeaver. * * <p>See the PetClinic sample application for a full example of this * ClassLoader in action. * * <p><b>NOTE:</b> Requires Apache Tomcat version 5.0 or higher. * * @author Costin Leau * @author Juergen Hoeller * @since 2.0 * @see #addTransformer * @see #getThrowawayClassLoader * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver */ public class TomcatInstrumentableClassLoader extends WebappClassLoader { private static final String CLASS_SUFFIX = ".class"; /** Use an internal WeavingTransformer */ private final WeavingTransformer weavingTransformer;//转换织入者 /** * Create a new <code>TomcatInstrumentableClassLoader</code> using the * current context class loader. * @see #TomcatInstrumentableClassLoader(ClassLoader) */ public TomcatInstrumentableClassLoader() { super(); this.weavingTransformer = new WeavingTransformer(this); } /** * Create a new <code>TomcatInstrumentableClassLoader</code> with the * supplied class loader as parent. * @param parent the parent {@link ClassLoader} to be used */ public TomcatInstrumentableClassLoader(ClassLoader parent) { super(parent); this.weavingTransformer = new WeavingTransformer(this); } /** * Delegate for LoadTimeWeaver's <code>addTransformer</code> method. * Typically called through ReflectiveLoadTimeWeaver. * @see org.springframework.instrument.classloading.LoadTimeWeaver#addTransformer * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver */ public void addTransformer(ClassFileTransformer transformer) { this.weavingTransformer.addTransformer(transformer); } /** * Delegate for LoadTimeWeaver's <code>getThrowawayClassLoader</code> method. * Typically called through ReflectiveLoadTimeWeaver. * @see org.springframework.instrument.classloading.LoadTimeWeaver#getThrowawayClassLoader * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver */ public ClassLoader getThrowawayClassLoader() { WebappClassLoader tempLoader = new WebappClassLoader(); // Use reflection to copy all the fields since most of them are private // on pre-5.5 Tomcat. shallowCopyFieldState(this, tempLoader); return tempLoader; } @Override protected ResourceEntry findResourceInternal(String name, String path) { //在加载查询资源时实现类转换 ResourceEntry entry = super.findResourceInternal(name, path); // Postpone String parsing as much as possible (it is slow). if (entry != null && entry.binaryContent != null && path.endsWith(CLASS_SUFFIX)) { String className = (name.endsWith(CLASS_SUFFIX) ? name.substring(0, name.length() - CLASS_SUFFIX.length()) : name); byte[] transformed = this.weavingTransformer.transformIfNecessary(className, entry.binaryContent); entry.binaryContent = transformed; } return entry; } @Override public String toString() { StringBuilder sb = new StringBuilder(getClass().getName()); sb.append("\r\n"); sb.append(super.toString()); return sb.toString(); } // The code below is originally taken from ReflectionUtils and optimized for // local usage. There is no dependency on ReflectionUtils to keep this class // self-contained (since it gets deployed into Tomcat's server class loader). /** * [Given] [the source object] and [the destination], (which must be the same class * or a subclass), [copy][all fields, including inherited fields]. [Designed] [to * work on] [objects] (with public no-arg constructors). * 给定源对象和目标对象,二者必须是同类型或子类型 * 拷贝包括继承属性在内的所有属性值 * 该方法设计用于不带参数的公有构造函数对象 * @throws IllegalArgumentException if arguments are incompatible or either * is <code>null</code> */ private static void shallowCopyFieldState(final Object src, final Object dest) throws IllegalArgumentException { if (src == null) { throw new IllegalArgumentException("Source for field copy cannot be null"); } if (dest == null) { throw new IllegalArgumentException("Destination for field copy cannot be null"); } Class targetClass = findCommonAncestor(src.getClass(), dest.getClass()); // Keep backing up the inheritance hierarchy. do { // Copy each field declared on this class unless it's static or // file. Field[] fields = targetClass.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; // Skip static and final fields (the old FieldFilter) // do not copy resourceEntries - it's a cache that holds class entries. if (!(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()) || field.getName().equals("resourceEntries"))) { try { // copy the field (the old FieldCallback) field.setAccessible(true); Object srcValue = field.get(src); field.set(dest, srcValue); } catch (IllegalAccessException ex) { throw new IllegalStateException( "Shouldn't be illegal to access field '" + fields[i].getName() + "': " + ex); } } } targetClass = targetClass.getSuperclass();//遍历所有父类 } while (targetClass != null && targetClass != Object.class); } private static Class findCommonAncestor(Class one, Class two) throws IllegalArgumentException { Class ancestor = one; while (ancestor != Object.class || ancestor != null) { if (ancestor.isAssignableFrom(two)) { return ancestor; } ancestor = ancestor.getSuperclass(); } // try the other class hierarchy ancestor = two; while (ancestor != Object.class || ancestor != null) { if (ancestor.isAssignableFrom(one)) { return ancestor; } ancestor = ancestor.getSuperclass(); } return null; } }
3、WeavingTransformer:基于ClassFileTransformer的编织者,允许一系列转换者(transformer)织入到类字节码中。
把目标比作衣服,transformer就是衣服上的装饰,而WeavingTransformer就是缝纫机
package org.springframework.instrument.classloading; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.List; /** * [ClassFileTransformer-based weaver], [allowing for] [a list of transformers] [to be * applied on] [a class byte array]. Normally used inside class loaders. *基于ClassFileTransformer的编织者,允许一系列转换者(transformer)织入到类字节码中。 *通常用在类加载器内 * <p>Note: [This class] is [deliberately implemented] [for minimal external dependencies], * [since it [is included] in weaver jars (to be deployed into application servers)]. *此类尽量少的使用外部引用,因为它被包含在织入者jar包内 * @author Rod Johnson * @author Costin Leau * @author Juergen Hoeller * @since 2.0 */ public class WeavingTransformer { private final ClassLoader classLoader; private final List<ClassFileTransformer> transformers = new ArrayList<ClassFileTransformer>(); /** * Create a new WeavingTransformer for the given class loader. * @param classLoader the ClassLoader to build a transformer for */ public WeavingTransformer(ClassLoader classLoader) { if (classLoader == null) { throw new IllegalArgumentException("ClassLoader must not be null"); } this.classLoader = classLoader; } /** * Add a class file transformer to be applied by this weaver. * 添加可以织入的转换者 * @param transformer the class file transformer to register */ public void addTransformer(ClassFileTransformer transformer) { if (transformer == null) { throw new IllegalArgumentException("Transformer must not be null"); } this.transformers.add(transformer); } /** * Apply transformation on a given class byte definition. * The method will always return a non-null byte array (if no transformation has taken place * the array content will be identical to the original one). * @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass) * @param bytes class byte definition * @return (possibly transformed) class byte definition */ public byte[] transformIfNecessary(String className, byte[] bytes) { String internalName = className.replace(".", "/"); return transformIfNecessary(className, internalName, bytes, null); } /** * Apply transformation on a given class byte definition. * 在一个给定的class字节码中实施转换 * The method will always return a non-null byte array (if no transformation has taken place * the array content will be identical to the original one). * 该函数返回非null值,如果没有转换则返回本身 * @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass) * @param internalName class name internal name in / format (i.e. some/package/SomeClass) * @param bytes class byte definition * @param pd protection domain to be used (can be null) * @return (possibly transformed) class byte definition */ public byte[] transformIfNecessary(String className, String internalName, byte[] bytes, ProtectionDomain pd) { byte[] result = bytes; for (ClassFileTransformer cft : this.transformers) {//遍历所有转换者,依次转换 try { //转换的内容在ClassFileTransformer的transform内执行 byte[] transformed = cft.transform(this.classLoader, internalName, null, pd, result); if (transformed != null) { result = transformed; } } catch (IllegalClassFormatException ex) { throw new IllegalStateException("Class file transformation failed", ex); } } return result; } }