曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成 (3)

这里提到了,这些转换器(即ClassFileTransformer)主要用于织入其他字节码来改变原始class的行为。目前,仅org.apache.catalina.loader.WebappClassLoaderBase实现了这个接口。

那我们就看看实现类的逻辑:

org.apache.catalina.loader.WebappClassLoaderBase //用来保存add进来的ClassFileTransformer private final List<ClassFileTransformer> transformers = new CopyOnWriteArrayList<ClassFileTransformer>(); @Override public void addTransformer(ClassFileTransformer transformer) { if (transformer == null) { throw new IllegalArgumentException(sm.getString( "webappClassLoader.addTransformer.illegalArgument", getContextName())); } // 添加到了一个transformers字段里 this.transformers.add(transformer); log.info(sm.getString("webappClassLoader.addTransformer", transformer, getContextName())); }

接下来,我们看看transformers在什么时候被使用:

/** * Find specified resource in local repositories. * * @return the loaded resource, or null if the resource isn't found */ protected ResourceEntry findResourceInternal(final String name, final String path, final boolean manifestRequired) { // 这前面很多代码,都是去tomcat的各种类路径下(自己的lib、webapp的lib下)查找class字节码 ... if (isClassResource && entry.binaryContent != null && this.transformers.size() > 0) { // If the resource is a class just being loaded, decorate it // with any attached transformers String className = name.endsWith(CLASS_FILE_SUFFIX) ? name.substring(0, name.length() - CLASS_FILE_SUFFIX.length()) : name; String internalName = className.replace(".", "http://www.likecs.com/"); for (ClassFileTransformer transformer : this.transformers) { try { // 这里,就是对获取到的原始字节码进行transform,该方法返回值就是修改过的字节码 byte[] transformed = transformer.transform( this, internalName, null, null, entry.binaryContent ); if (transformed != null) { // 改后的字节码存起来,等待下一次循环时,作为新的input entry.binaryContent = transformed; } } catch (IllegalClassFormatException e) { log.error(sm.getString("webappClassLoader.transformError", name), e); return null; } } } return entry; }

所以,大家从这里也看得出来,tomcat实现ltw的思路,也是自定义classloader,在classloader里做文章。

其他的容器呢,我们就不一一分析了。接下来,我们介绍另一种方式,即非容器环境下,使用的agent机制。

ltw实现方式之java instrumentation(适用非容器环境)

前面说了,容器环境下,一般各大容器为了支持ltw,实现了自己的classloader。

但假设是非容器环境,比如单独的java应用,比如spring boot应用呢?

这时候一般使用的sun.misc.Launcher.AppClassLoader,但这个是不支持add ClassFileTransformer的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjzzy.html