Skip to content

Commit

Permalink
[#11908] Improve JVM compatibility of the bootstrap classloader
Browse files Browse the repository at this point in the history
  • Loading branch information
emeroad committed Jan 6, 2025
1 parent 91ef90c commit a36ab5a
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ public ClassInjectorFactory(InstrumentEngine instrumentEngine, BootstrapCore boo
}

public ClassInjector newClassInjector(PluginConfig pluginConfig) {
return new JarProfilerPluginClassInjector(pluginConfig, instrumentEngine, bootstrapCore);
return PluginClassInjector.from(pluginConfig, instrumentEngine, bootstrapCore);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,91 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.navercorp.pinpoint.profiler.instrument.classloading;

import com.navercorp.pinpoint.exception.PinpointException;
import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine;
import com.navercorp.pinpoint.profiler.plugin.PluginConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.InputStream;
import java.net.URLClassLoader;
import java.util.Objects;

/**
* @author Woonduk Kang(emeroad)
* @author Jongho Moon
* @author jaehong.kim
*/
public interface PluginClassInjector extends ClassInjector {
public class PluginClassInjector implements ClassInjector {
private final Logger logger = LogManager.getLogger(PluginClassInjector.class);

private final ClassLoader bootstrapClassLoader = Object.class.getClassLoader();

private final BootstrapCore bootstrapCore;
private final ClassInjector bootstrapClassLoaderHandler;
private final ClassInjector urlClassLoaderHandler;
private final ClassInjector plainClassLoaderHandler;

public static PluginClassInjector from(PluginConfig pluginConfig, InstrumentEngine instrumentEngine, BootstrapCore bootstrapCore) {
Objects.requireNonNull(pluginConfig, "pluginConfig");

ClassInjector bootstrapClassLoaderHandler = new BootstrapClassLoaderHandler(pluginConfig, instrumentEngine);
ClassInjector urlClassLoaderHandler = new URLClassLoaderHandler(pluginConfig);

final DefineClass defineClass = instrumentEngine.getDefineClass();
ClassInjector plainClassLoaderHandler = new PlainClassLoaderHandler(defineClass, pluginConfig);
return new PluginClassInjector(bootstrapCore, bootstrapClassLoaderHandler, urlClassLoaderHandler, plainClassLoaderHandler);
}

public PluginClassInjector(BootstrapCore bootstrapCore,
ClassInjector bootstrapClassInjector,
ClassInjector urlClassLoaderInjector,
ClassInjector plainClassLoaderInjector) {
this.bootstrapCore = Objects.requireNonNull(bootstrapCore, "bootstrapCore");
this.bootstrapClassLoaderHandler = Objects.requireNonNull(bootstrapClassInjector, "bootstrapClassInjector");
this.urlClassLoaderHandler = Objects.requireNonNull(urlClassLoaderInjector, "urlClassLoaderInjector");
this.plainClassLoaderHandler = Objects.requireNonNull(plainClassLoaderInjector, "plainClassLoaderInjector");
}

@Override
public <T> Class<? extends T> injectClass(ClassLoader classLoader, String className) {
try {
if (bootstrapCore.isBootstrapPackage(className)) {
return bootstrapCore.loadClass(className);
}

if (bootstrapClassLoader == classLoader) {
return bootstrapClassLoaderHandler.injectClass(null, className);
} else if (classLoader instanceof URLClassLoader) {
return urlClassLoaderHandler.injectClass(classLoader, className);
} else {
return plainClassLoaderHandler.injectClass(classLoader, className);
}
} catch (Throwable e) {
// fixed for LinkageError
logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e);
throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e);
}
}

PluginConfig getPluginConfig();
}
@Override
public InputStream getResourceAsStream(ClassLoader targetClassLoader, String internalName) {
try {
if (bootstrapCore.isBootstrapPackageByInternalName(internalName)) {
return bootstrapCore.openStream(internalName);
}
if (targetClassLoader == null) {
return bootstrapClassLoaderHandler.getResourceAsStream(null, internalName);
} else if (targetClassLoader instanceof URLClassLoader) {
final URLClassLoader urlClassLoader = (URLClassLoader) targetClassLoader;
return urlClassLoaderHandler.getResourceAsStream(urlClassLoader, internalName);
} else {
return plainClassLoaderHandler.getResourceAsStream(targetClassLoader, internalName);
}
} catch (Throwable e) {
logger.warn("Failed to load plugin resource as stream {} with classLoader {}", internalName, targetClassLoader, e);
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@
import java.util.Collections;
import java.util.List;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

/**
* @author Woonduk Kang(emeroad)
*/
public class JarProfilerPluginClassInjectorTest {
public class PluginClassInjectorTest {

public static final String CONTEXT_TYPE_MATCH_CLASS_LOADER = "org.springframework.context.support.ContextTypeMatchClassLoader";

Expand Down Expand Up @@ -119,4 +123,20 @@ private Plugin<?> getMockPlugin(Class<?> clazz) throws Exception {
return new JarPlugin<>(pluginJar, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
}

@Test
public void testInjectClass_bootstrap() {
BootstrapCore bootstrapCore = new BootstrapCore(Collections.emptyList());
ClassInjector boot = mock(ClassInjector.class);
ClassInjector url = mock(ClassInjector.class);
ClassInjector plain = mock(ClassInjector.class);

ClassInjector injector = new PluginClassInjector(bootstrapCore, boot, url, plain);
ClassLoader booptstrapCl = Object.class.getClassLoader();
injector.injectClass(booptstrapCl, "java.lang.String");
injector.injectClass(this.getClass().getClassLoader(), "Test");

verify(boot).injectClass(booptstrapCl, "java.lang.String");
verify(boot, never()).injectClass(this.getClass().getClassLoader(), "Test");
}

}

0 comments on commit a36ab5a

Please sign in to comment.