diff --git a/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjectorFactory.java b/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjectorFactory.java index 8e10c725d682..220804e05e56 100644 --- a/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjectorFactory.java +++ b/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjectorFactory.java @@ -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); } } diff --git a/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjector.java b/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjector.java deleted file mode 100644 index d9e351278d70..000000000000 --- a/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjector.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * 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 Jongho Moon - * @author jaehong.kim - */ -public class JarProfilerPluginClassInjector implements ClassInjector { - private final Logger logger = LogManager.getLogger(JarProfilerPluginClassInjector.class); - - private final BootstrapCore bootstrapCore; - private final ClassInjector bootstrapClassLoaderHandler; - private final ClassInjector urlClassLoaderHandler; - private final ClassInjector plainClassLoaderHandler; - - public JarProfilerPluginClassInjector(PluginConfig pluginConfig, InstrumentEngine instrumentEngine, BootstrapCore bootstrapCore) { - Objects.requireNonNull(pluginConfig, "pluginConfig"); - - this.bootstrapCore = Objects.requireNonNull(bootstrapCore, "bootstrapCore"); - this.bootstrapClassLoaderHandler = new BootstrapClassLoaderHandler(pluginConfig, instrumentEngine); - this.urlClassLoaderHandler = new URLClassLoaderHandler(pluginConfig); - - final DefineClass defineClass = instrumentEngine.getDefineClass(); - this.plainClassLoaderHandler = new PlainClassLoaderHandler(defineClass, pluginConfig); - } - - @Override - @SuppressWarnings("unchecked") - public Class injectClass(ClassLoader classLoader, String className) { - try { - if (bootstrapCore.isBootstrapPackage(className)) { - return bootstrapCore.loadClass(className); - } - if (classLoader == null) { - return bootstrapClassLoaderHandler.injectClass(null, className); - } else if (classLoader instanceof URLClassLoader) { - final URLClassLoader urlClassLoader = (URLClassLoader) classLoader; - return urlClassLoaderHandler.injectClass(urlClassLoader, 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); - } - } - - @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; - } - } -} \ No newline at end of file diff --git a/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PluginClassInjector.java b/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PluginClassInjector.java index fec2f9bdd6d1..d9866e20390a 100644 --- a/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PluginClassInjector.java +++ b/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PluginClassInjector.java @@ -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 Class 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; + } + } +} \ No newline at end of file diff --git a/agent-module/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjectorTest.java b/agent-module/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/PluginClassInjectorTest.java similarity index 85% rename from agent-module/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjectorTest.java rename to agent-module/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/PluginClassInjectorTest.java index cdfbb22c6901..72d9497ba652 100644 --- a/agent-module/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjectorTest.java +++ b/agent-module/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/PluginClassInjectorTest.java @@ -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"; @@ -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"); + } + } \ No newline at end of file