mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-16 16:28:48 +10:00
Merge pull request #454 from lioolli/master
Modified plugin class loading mechanism
This commit is contained in:
-124
@@ -1,124 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014 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.plugin;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder;
|
||||
import com.navercorp.pinpoint.test.plugin.JvmArgument;
|
||||
import com.navercorp.pinpoint.test.plugin.JvmVersion;
|
||||
import com.navercorp.pinpoint.test.plugin.OnClassLoader;
|
||||
import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
@RunWith(PinpointPluginTestSuite.class)
|
||||
@JvmVersion(6)
|
||||
@OnClassLoader(child=false)
|
||||
@JvmArgument("-Dcom.navercorp.pinpoint.plugin.classloader=" + Java6PluginClassLoaderIT.JAVA_6_PLUGIN_CLASSLOADER)
|
||||
public class Java6PluginClassLoaderIT {
|
||||
public static final String JAVA_6_PLUGIN_CLASSLOADER = "com.navercorp.pinpoint.profiler.plugin.Java6PluginClassLoader";
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
ClassLoader parent = ClassLoader.getSystemClassLoader();
|
||||
ClassLoader child = createChildClassLoader(parent);
|
||||
|
||||
final int run = 10000;
|
||||
final int threadNum = 16;
|
||||
Thread[] thread = new Thread[threadNum];
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
if (i % 2 == 0) {
|
||||
thread[i] = new Thread(new Parent(parent, child, run));
|
||||
} else {
|
||||
thread[i] = new Thread(new Child(child, run));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
thread[i].start();
|
||||
}
|
||||
|
||||
System.out.println("Wait workers...");
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
thread[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader createChildClassLoader(ClassLoader parent) throws Exception {
|
||||
Class<? extends ClassLoader> type = PluginTestVerifierHolder.getInstance().getClass().getClassLoader().loadClass(JAVA_6_PLUGIN_CLASSLOADER).asSubclass(ClassLoader.class);
|
||||
Constructor<? extends ClassLoader> c = type.getConstructor(URL[].class, ClassLoader.class);
|
||||
return c.newInstance(new URL[0], parent);
|
||||
}
|
||||
|
||||
|
||||
private static class Parent implements Runnable {
|
||||
private final ClassLoader parent;
|
||||
private final ClassLoader child;
|
||||
private final int count;
|
||||
|
||||
public Parent(ClassLoader parent, ClassLoader child, int count) {
|
||||
this.parent = parent;
|
||||
this.child = child;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
System.out.println(this + ": " + i);
|
||||
synchronized(parent) {
|
||||
try {
|
||||
child.loadClass("no.such.Class");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Child implements Runnable {
|
||||
private final ClassLoader child;
|
||||
private final int count;
|
||||
|
||||
public Child(ClassLoader child, int count) {
|
||||
this.child = child;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
System.out.println(this + ": " + i);
|
||||
synchronized(child) {
|
||||
try {
|
||||
child.loadClass("no.such.Class");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-2
@@ -91,8 +91,6 @@ public interface ProfilerPluginContext {
|
||||
|
||||
public InterceptorGroup getInterceptorGroup(String name);
|
||||
|
||||
public PluginClassLoaderFactory getClassLoaderFactory();
|
||||
|
||||
/**
|
||||
* Add a {@link ApplicationTypeDetector} to Pinpoint agent.
|
||||
*
|
||||
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014 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.plugin;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public class Java7PluginClassLoaderTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
ClassLoader parent = ClassLoader.getSystemClassLoader();
|
||||
ClassLoader child = new Java7PluginClassLoader(new URL[0], parent);
|
||||
|
||||
final int run = 10000;
|
||||
final int threadNum = 16;
|
||||
Thread[] thread = new Thread[threadNum];
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
if (i % 2 == 0) {
|
||||
thread[i] = new Thread(new Parent(parent, child, run));
|
||||
} else {
|
||||
thread[i] = new Thread(new Child(child, run));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
thread[i].start();
|
||||
}
|
||||
|
||||
System.out.println("Wait workers...");
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
thread[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class Parent implements Runnable {
|
||||
private final ClassLoader parent;
|
||||
private final ClassLoader child;
|
||||
private final int count;
|
||||
|
||||
public Parent(ClassLoader parent, ClassLoader child, int count) {
|
||||
this.parent = parent;
|
||||
this.child = child;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
synchronized(parent) {
|
||||
try {
|
||||
child.loadClass("no.such.Class");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Child implements Runnable {
|
||||
private final ClassLoader child;
|
||||
private final int count;
|
||||
|
||||
public Child(ClassLoader child, int count) {
|
||||
this.child = child;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
synchronized(child) {
|
||||
try {
|
||||
child.loadClass("no.such.Class");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014 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;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.instrument.UnmodifiableClassException;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public class ClassLoaderResolver {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public Class<? extends ClassLoader> resolve(Instrumentation inst) {
|
||||
String pluginClassLoaderName = null;
|
||||
|
||||
String specified = System.getProperty("com.navercorp.pinpoint.plugin.classloader");
|
||||
|
||||
if (specified == null) {
|
||||
pluginClassLoaderName = resolveClassLoaderType();
|
||||
} else {
|
||||
pluginClassLoaderName = specified;
|
||||
}
|
||||
|
||||
logger.info("Use plugin class loader: " + pluginClassLoaderName);
|
||||
|
||||
boolean redefineClassLoader = "com.navercorp.pinpoint.profiler.plugin.Java6PluginClassLoader".equals(pluginClassLoaderName);
|
||||
|
||||
try {
|
||||
if (redefineClassLoader) {
|
||||
retransformClassLoader(inst);
|
||||
}
|
||||
|
||||
return Class.forName(pluginClassLoaderName).asSubclass(ClassLoader.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new NoClassDefFoundError("Cannot find plugin class loader: " + pluginClassLoaderName);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Failed to prepare " + pluginClassLoaderName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveClassLoaderType() {
|
||||
String pluginClassLoaderName;
|
||||
boolean java6 = isJava6();
|
||||
boolean unsafe = hasUnsafe();
|
||||
|
||||
if (java6) {
|
||||
if (unsafe) {
|
||||
pluginClassLoaderName = "com.navercorp.pinpoint.profiler.plugin.Java6UnsafePluginClassLoader";
|
||||
} else {
|
||||
pluginClassLoaderName = "com.navercorp.pinpoint.profiler.plugin.Java6PluginClassLoader";
|
||||
}
|
||||
} else {
|
||||
pluginClassLoaderName = "com.navercorp.pinpoint.profiler.plugin.Java7PluginClassLoader";
|
||||
}
|
||||
return pluginClassLoaderName;
|
||||
}
|
||||
|
||||
private void retransformClassLoader(Instrumentation inst) throws UnmodifiableClassException {
|
||||
ClassLoaderTransformer transformer = new ClassLoaderTransformer();
|
||||
inst.addTransformer(transformer, true);
|
||||
inst.retransformClasses(ClassLoader.class);
|
||||
inst.removeTransformer(transformer);
|
||||
}
|
||||
|
||||
private boolean hasUnsafe() {
|
||||
try {
|
||||
Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe").setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isJava6() {
|
||||
try {
|
||||
ClassLoader.class.getDeclaredMethod("registerAsParallelCapable");
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class ClassLoaderTransformer implements ClassFileTransformer {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Override
|
||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
|
||||
logger.info("in transform: " + className);
|
||||
|
||||
if (className.equals("java/lang/ClassLoader")) {
|
||||
logger.info("Transform ClassLoader");
|
||||
|
||||
try {
|
||||
ClassPool classPool = new ClassPool(true);
|
||||
CtClass c = classPool.get("java.lang.ClassLoader");
|
||||
CtMethod m = c.getMethod("loadClass", "(Ljava/lang/String;Z)Ljava/lang/Class;");
|
||||
|
||||
m.insertBefore("com.navercorp.pinpoint.bootstrap.ClassLoaderLock.lock(this);");
|
||||
m.insertAfter("com.navercorp.pinpoint.bootstrap.ClassLoaderLock.unlock(this);", true);
|
||||
|
||||
logger.info("Transform ClassLoader Finished");
|
||||
|
||||
return c.toBytecode();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,6 @@ package com.navercorp.pinpoint.profiler;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -38,9 +36,7 @@ import com.navercorp.pinpoint.bootstrap.instrument.ByteCodeInstrumentor;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLoggerBinder;
|
||||
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
|
||||
import com.navercorp.pinpoint.bootstrap.sampler.Sampler;
|
||||
import com.navercorp.pinpoint.common.plugin.PluginLoader;
|
||||
import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService;
|
||||
import com.navercorp.pinpoint.common.trace.ServiceType;
|
||||
import com.navercorp.pinpoint.profiler.context.DefaultServerMetaDataHolder;
|
||||
@@ -53,8 +49,8 @@ import com.navercorp.pinpoint.profiler.interceptor.InterceptorRegistryBinder;
|
||||
import com.navercorp.pinpoint.profiler.interceptor.bci.JavaAssistByteCodeInstrumentor;
|
||||
import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinder;
|
||||
import com.navercorp.pinpoint.profiler.monitor.AgentStatMonitor;
|
||||
import com.navercorp.pinpoint.profiler.plugin.DefaultPluginClassLoaderFactory;
|
||||
import com.navercorp.pinpoint.profiler.plugin.DefaultProfilerPluginContext;
|
||||
import com.navercorp.pinpoint.profiler.plugin.ProfilerPluginLoader;
|
||||
import com.navercorp.pinpoint.profiler.receiver.CommandDispatcher;
|
||||
import com.navercorp.pinpoint.profiler.receiver.service.EchoService;
|
||||
import com.navercorp.pinpoint.profiler.receiver.service.ThreadDumpService;
|
||||
@@ -106,7 +102,6 @@ public class DefaultAgent implements Agent {
|
||||
private final InterceptorRegistryBinder interceptorRegistryBinder;
|
||||
private final ServiceTypeRegistryService serviceTypeRegistryService;
|
||||
|
||||
private final DefaultPluginClassLoaderFactory pluginClassLoaderFactory;
|
||||
private final List<DefaultProfilerPluginContext> pluginContexts;
|
||||
|
||||
|
||||
@@ -160,9 +155,7 @@ public class DefaultAgent implements Agent {
|
||||
logger.info("DefaultAgent classLoader:{}", this.getClass().getClassLoader());
|
||||
}
|
||||
|
||||
Class<? extends ClassLoader> classLoaderType = new ClassLoaderResolver().resolve(instrumentation);
|
||||
pluginClassLoaderFactory = new DefaultPluginClassLoaderFactory(classLoaderType, agentOption.getPluginJars());
|
||||
pluginContexts = loadProfilerPlugins(agentOption.getPluginJars());
|
||||
pluginContexts = loadPlugins(agentOption);
|
||||
|
||||
this.classFileTransformer = new ClassFileTransformerDispatcher(this, byteCodeInstrumentor, pluginContexts);
|
||||
retransformService.setRetransformEventListener(classFileTransformer);
|
||||
@@ -199,6 +192,10 @@ public class DefaultAgent implements Agent {
|
||||
this.agentStatMonitor = new AgentStatMonitor(this.statDataSender, this.agentInformation.getAgentId(), this.agentInformation.getStartTime());
|
||||
}
|
||||
|
||||
protected List<DefaultProfilerPluginContext> loadPlugins(AgentOption agentOption) {
|
||||
return new ProfilerPluginLoader(this).load(agentOption.getPluginJars());
|
||||
}
|
||||
|
||||
|
||||
private CommandDispatcher createCommandDispatcher() {
|
||||
CommandDispatcher commandDispatcher = new CommandDispatcher();
|
||||
@@ -207,22 +204,6 @@ public class DefaultAgent implements Agent {
|
||||
return commandDispatcher;
|
||||
}
|
||||
|
||||
private List<DefaultProfilerPluginContext> loadProfilerPlugins(URL[] pluginJars) {
|
||||
List<ProfilerPlugin> plugins = PluginLoader.load(ProfilerPlugin.class, pluginJars);
|
||||
List<DefaultProfilerPluginContext> pluginContexts = new ArrayList<DefaultProfilerPluginContext>(plugins.size());
|
||||
|
||||
for (ProfilerPlugin plugin : plugins) {
|
||||
logger.info("Loading plugin: {}", plugin.getClass().getName());
|
||||
|
||||
DefaultProfilerPluginContext context = new DefaultProfilerPluginContext(this);
|
||||
plugin.setup(context);
|
||||
context.markInitialized();
|
||||
pluginContexts.add(context);
|
||||
}
|
||||
|
||||
return pluginContexts;
|
||||
}
|
||||
|
||||
public ByteCodeInstrumentor getByteCodeInstrumentor() {
|
||||
return byteCodeInstrumentor;
|
||||
}
|
||||
@@ -383,10 +364,6 @@ public class DefaultAgent implements Agent {
|
||||
return serviceTypeRegistryService;
|
||||
}
|
||||
|
||||
public DefaultPluginClassLoaderFactory getPluginClassLoaderFactory() {
|
||||
return pluginClassLoaderFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
synchronized (this) {
|
||||
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.plugin;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.PluginClassLoaderFactory;
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
|
||||
public class DefaultPluginClassLoaderFactory implements PluginClassLoaderFactory {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultPluginClassLoaderFactory.class);
|
||||
private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager();
|
||||
|
||||
private final Constructor<? extends ClassLoader> classLoaderConstructor;
|
||||
private final URL[] pluginJars;
|
||||
private final ConcurrentHashMap<ClassLoader, ClassLoader> cache = new ConcurrentHashMap<ClassLoader, ClassLoader>();
|
||||
private final AtomicReference<ClassLoader> forBootstrapClassLoader = new AtomicReference<ClassLoader>();
|
||||
|
||||
|
||||
|
||||
public DefaultPluginClassLoaderFactory(Class<? extends ClassLoader> classLoaderType, URL[] pluginJars) {
|
||||
try {
|
||||
this.classLoaderConstructor = classLoaderType.getDeclaredConstructor(URL[].class, ClassLoader.class);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Cannot find constructor with parameter (URL[], ClassLoader): " + classLoaderType);
|
||||
}
|
||||
|
||||
this.pluginJars = pluginJars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader get(ClassLoader loader) {
|
||||
if (loader == null) {
|
||||
// boot class loader
|
||||
return getForBootstrap();
|
||||
} else {
|
||||
return getForPlain(loader);
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader getForPlain(ClassLoader loader) {
|
||||
final ClassLoader forPlugin = cache.get(loader);
|
||||
if (forPlugin != null) {
|
||||
return forPlugin;
|
||||
}
|
||||
|
||||
final ClassLoader newInstance = createPluginClassLoader(pluginJars, loader);
|
||||
final ClassLoader before = cache.putIfAbsent(loader, newInstance);
|
||||
if (before == null) {
|
||||
return newInstance;
|
||||
} else {
|
||||
close (newInstance);
|
||||
return before;
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader getForBootstrap() {
|
||||
final ClassLoader forPlugin = forBootstrapClassLoader.get();
|
||||
|
||||
if (forPlugin != null) {
|
||||
return forPlugin;
|
||||
}
|
||||
|
||||
// Strictly, should pass null as parent class loader.
|
||||
// But if so, All the types used by interceptors have to be loaded by bootstrap class loader.
|
||||
// So we use system class loader as parent.
|
||||
final ClassLoader newInstance = createPluginClassLoader(pluginJars, ClassLoader.getSystemClassLoader());
|
||||
boolean success = forBootstrapClassLoader.compareAndSet(null, newInstance);
|
||||
|
||||
if (success) {
|
||||
return newInstance;
|
||||
} else {
|
||||
close (newInstance);
|
||||
return forBootstrapClassLoader.get();
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader createPluginClassLoader(final URL[] urls, final ClassLoader parent) {
|
||||
if (SECURITY_MANAGER != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
||||
public ClassLoader run() {
|
||||
return createPluginClassLoader0(urls, parent);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return createPluginClassLoader0(urls, parent);
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader createPluginClassLoader0(URL[] urls, ClassLoader parent) {
|
||||
try {
|
||||
return (ClassLoader)classLoaderConstructor.newInstance(urls, parent);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Failed to create plugin classloader instance", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void close(ClassLoader classLoader) {
|
||||
if (classLoader == null) {
|
||||
return;
|
||||
}
|
||||
// after jdk 1.7
|
||||
if (classLoader instanceof Closeable) {
|
||||
try {
|
||||
((Closeable)classLoader).close();
|
||||
} catch (IOException e) {
|
||||
logger.warn("ClassLoader.close() fail. Cause: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+6
-6
@@ -29,7 +29,6 @@ import com.navercorp.pinpoint.bootstrap.context.TraceContext;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.ByteCodeInstrumentor;
|
||||
import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroup;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.PluginClassLoaderFactory;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginContext;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.transformer.ClassFileTransformerBuilder;
|
||||
import com.navercorp.pinpoint.profiler.DefaultAgent;
|
||||
@@ -38,6 +37,7 @@ import com.navercorp.pinpoint.profiler.util.NameValueList;
|
||||
|
||||
public class DefaultProfilerPluginContext implements ProfilerPluginContext {
|
||||
private final DefaultAgent agent;
|
||||
private final ProfilerPluginClassLoader classInjector;
|
||||
|
||||
private final List<ApplicationTypeDetector> serverTypeDetectors = new ArrayList<ApplicationTypeDetector>();
|
||||
private final List<ClassFileTransformer> classTransformers = new ArrayList<ClassFileTransformer>();
|
||||
@@ -53,8 +53,9 @@ public class DefaultProfilerPluginContext implements ProfilerPluginContext {
|
||||
private boolean initialized = false;
|
||||
|
||||
|
||||
public DefaultProfilerPluginContext(DefaultAgent agent) {
|
||||
public DefaultProfilerPluginContext(DefaultAgent agent, ProfilerPluginClassLoader classInjector) {
|
||||
this.agent = agent;
|
||||
this.classInjector = classInjector;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,10 +153,9 @@ public class DefaultProfilerPluginContext implements ProfilerPluginContext {
|
||||
serverTypeDetectors.add(detector);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginClassLoaderFactory getClassLoaderFactory() {
|
||||
return agent.getPluginClassLoaderFactory();
|
||||
|
||||
public ProfilerPluginClassLoader getClassInjector() {
|
||||
return classInjector;
|
||||
}
|
||||
|
||||
public List<ClassFileTransformer> getClassEditors() {
|
||||
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright 2014 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.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Collection;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.LoaderClassPath;
|
||||
import javassist.NotFoundException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public class JarProfilerPluginClassLoader implements ProfilerPluginClassLoader {
|
||||
private static final Logger logger = LoggerFactory.getLogger(JarProfilerPluginClassLoader.class);
|
||||
|
||||
private static final Method ADD_URL;
|
||||
private static final Method DEFINE_CLASS;
|
||||
|
||||
static {
|
||||
try {
|
||||
ADD_URL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
ADD_URL.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Cannot access URLClassLoader.addURL(URL)", e);
|
||||
}
|
||||
|
||||
try {
|
||||
DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
|
||||
DEFINE_CLASS.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static JarProfilerPluginClassLoader of(URL pluginJar) {
|
||||
try {
|
||||
JarFile jarFile = new JarFile(new File(pluginJar.toURI()));
|
||||
return new JarProfilerPluginClassLoader(pluginJar, jarFile);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to get JarFile {}", pluginJar, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final URL pluginJarURL;
|
||||
private final JarFile pluginJar;
|
||||
|
||||
|
||||
private JarProfilerPluginClassLoader(URL pluginJarURL, JarFile pluginJar) {
|
||||
this.pluginJarURL = pluginJarURL;
|
||||
this.pluginJar = pluginJar;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Class<? extends T> loadClass(ClassLoader classLoader, String className) {
|
||||
ClassLoader targetClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
|
||||
|
||||
try {
|
||||
if (targetClassLoader instanceof URLClassLoader) {
|
||||
return (Class<T>)loadFromURLClassLoader((URLClassLoader)targetClassLoader, className);
|
||||
} else {
|
||||
return (Class<T>)loadFromOtherClassLoader(targetClassLoader, className);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to load plugin class {} with classLoader {}", className, targetClassLoader, e);
|
||||
throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + targetClassLoader, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> loadFromURLClassLoader(URLClassLoader classLoader, String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
|
||||
URL[] urls = classLoader.getURLs();
|
||||
|
||||
boolean hasPluginJar = false;
|
||||
for (URL url : urls) {
|
||||
if (url.equals(pluginJarURL)) {
|
||||
hasPluginJar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPluginJar) {
|
||||
ADD_URL.invoke(classLoader, pluginJarURL);
|
||||
}
|
||||
|
||||
return classLoader.loadClass(className);
|
||||
}
|
||||
|
||||
private Class<?> loadFromOtherClassLoader(ClassLoader classLoader, String className) throws NotFoundException, IllegalArgumentException, IOException, CannotCompileException, IllegalAccessException, InvocationTargetException {
|
||||
ClassPool pool = new ClassPool();
|
||||
|
||||
pool.appendClassPath(new LoaderClassPath(classLoader));
|
||||
pool.appendClassPath(pluginJar.getName());
|
||||
|
||||
return loadFromOtherClassLoader(pool, classLoader, className);
|
||||
}
|
||||
|
||||
private Class<?> loadFromOtherClassLoader(ClassPool pool, ClassLoader classLoader, String className) throws NotFoundException, IOException, CannotCompileException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
Class<?> c = null;
|
||||
|
||||
try {
|
||||
c = classLoader.loadClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
CtClass ct = pool.get(className);
|
||||
|
||||
if (ct == null) {
|
||||
throw new NotFoundException(className);
|
||||
}
|
||||
|
||||
|
||||
CtClass superClass = ct.getSuperclass();
|
||||
|
||||
if (superClass != null) {
|
||||
loadFromOtherClassLoader(pool, classLoader, superClass.getName());
|
||||
}
|
||||
|
||||
CtClass[] interfaces = ct.getInterfaces();
|
||||
|
||||
for (CtClass i : interfaces) {
|
||||
loadFromOtherClassLoader(pool, classLoader, i.getName());
|
||||
}
|
||||
|
||||
Collection<String> refs = ct.getRefClasses();
|
||||
|
||||
for (String ref : refs) {
|
||||
try {
|
||||
loadFromOtherClassLoader(pool, classLoader, ref);
|
||||
} catch (NotFoundException e) {
|
||||
logger.warn("Skip a referenced class because of NotFoundException : ", e);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = ct.toBytecode();
|
||||
return (Class<?>)DEFINE_CLASS.invoke(classLoader, ct.getName(), bytes, 0, bytes.length);
|
||||
}
|
||||
}
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.plugin;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.ClassLoaderLock;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
* @author emeroad
|
||||
*/
|
||||
public class Java6PluginClassLoader extends URLClassLoader {
|
||||
|
||||
public Java6PluginClassLoader(URL[] urls, ClassLoader parent) {
|
||||
super(urls, parent);
|
||||
ClassLoaderLock.register(parent, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
ClassLoaderLock.lock(this);
|
||||
|
||||
try {
|
||||
Class<?> c = findLoadedClass(name);
|
||||
if (c == null) {
|
||||
try {
|
||||
c = getParent().loadClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
|
||||
if (c == null) {
|
||||
c = findClass(name);
|
||||
}
|
||||
}
|
||||
if (resolve) {
|
||||
resolveClass(c);
|
||||
}
|
||||
return c;
|
||||
} finally {
|
||||
ClassLoaderLock.unlock(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.plugin;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
* @author emeroad
|
||||
*/
|
||||
@SuppressWarnings("restriction")
|
||||
public class Java6UnsafePluginClassLoader extends URLClassLoader {
|
||||
|
||||
private static final Unsafe unsafe;
|
||||
|
||||
static {
|
||||
try {
|
||||
Field f = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
f.setAccessible(true);
|
||||
unsafe = (Unsafe)f.get(null);
|
||||
|
||||
// Ensure required classes are loaded
|
||||
while (!unsafe.tryMonitorEnter(Java6UnsafePluginClassLoader.class)) { }
|
||||
Java6UnsafePluginClassLoader.class.wait(0, 1);
|
||||
unsafe.monitorExit(Java6UnsafePluginClassLoader.class);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to get unsafe", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final ClassLoader parent;
|
||||
|
||||
public Java6UnsafePluginClassLoader(URL[] urls, ClassLoader parent) {
|
||||
super(urls, parent);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
Class<?> c = null;
|
||||
|
||||
synchronized (this) {
|
||||
c = findLoadedClass(name);
|
||||
|
||||
if (c == null) {
|
||||
try {
|
||||
while (!unsafe.tryMonitorEnter(parent)) {
|
||||
try {
|
||||
this.wait(0, 1);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Interrupted", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
c = parent.loadClass(name);
|
||||
} finally {
|
||||
unsafe.monitorExit(parent);
|
||||
}
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
||||
}
|
||||
|
||||
if (c == null) {
|
||||
c = findClass(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (resolve) {
|
||||
resolveClass(c);
|
||||
}
|
||||
|
||||
this.notify();
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -12,14 +12,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.navercorp.pinpoint.bootstrap.plugin;
|
||||
package com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public interface PluginClassLoaderFactory {
|
||||
public interface ProfilerPluginClassLoader {
|
||||
|
||||
public ClassLoader get(ClassLoader loader);
|
||||
public <T> Class<? extends T> loadClass(ClassLoader targetClassLoader, String className);
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright 2014 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.plugin;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
|
||||
import com.navercorp.pinpoint.common.plugin.PluginLoader;
|
||||
import com.navercorp.pinpoint.profiler.DefaultAgent;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public class ProfilerPluginLoader {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final DefaultAgent agent;
|
||||
|
||||
public ProfilerPluginLoader(DefaultAgent agent) {
|
||||
this.agent = agent;
|
||||
}
|
||||
|
||||
public List<DefaultProfilerPluginContext> load(URL[] pluginJars) {
|
||||
List<DefaultProfilerPluginContext> pluginContexts = new ArrayList<DefaultProfilerPluginContext>(pluginJars.length);
|
||||
|
||||
for (URL jar : pluginJars) {
|
||||
List<ProfilerPlugin> plugins = PluginLoader.load(ProfilerPlugin.class, new URL[] { jar });
|
||||
|
||||
for (ProfilerPlugin plugin : plugins) {
|
||||
logger.info("Loading plugin: {}", plugin.getClass().getName());
|
||||
|
||||
ProfilerPluginClassLoader classInjector = JarProfilerPluginClassLoader.of(jar);
|
||||
DefaultProfilerPluginContext context = new DefaultProfilerPluginContext(agent, classInjector);
|
||||
plugin.setup(context);
|
||||
context.markInitialized();
|
||||
pluginContexts.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return pluginContexts;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -60,23 +60,7 @@ public final class TypeUtils {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Class<T> loadClass(ClassLoader loader, String className) {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader backup = currentThread.getContextClassLoader();
|
||||
currentThread.setContextClassLoader(loader);
|
||||
|
||||
try {
|
||||
return (Class<T>)loader.loadClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new PinpointException("Cannot load class: " + className, e);
|
||||
} finally {
|
||||
currentThread.setContextClassLoader(backup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static <T extends Annotation> T findAnnotation(Annotation[] annotations, Class<T> type) {
|
||||
for (Annotation a : annotations) {
|
||||
if (a.annotationType() == type) {
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ public class AnnotatedInterceptorInjector implements MethodRecipe {
|
||||
}
|
||||
|
||||
int inject(ClassLoader targetClassLoader, InstrumentClass targetClass, MethodInfo targetMethod) throws Exception {
|
||||
Class<? extends Interceptor> interceptorType = TypeUtils.loadClass(targetClassLoader, interceptorClassName);
|
||||
Class<? extends Interceptor> interceptorType = pluginContext.getClassInjector().loadClass(targetClassLoader, interceptorClassName);
|
||||
InterceptorFactory factory = createInterceptorFactory(interceptorType);
|
||||
Interceptor interceptor = factory.getInterceptor(targetClassLoader, targetClass, targetMethod);
|
||||
|
||||
|
||||
+9
-10
@@ -29,7 +29,6 @@ import com.navercorp.pinpoint.bootstrap.plugin.annotation.TargetMethod;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Targets;
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
import com.navercorp.pinpoint.profiler.plugin.DefaultProfilerPluginContext;
|
||||
import com.navercorp.pinpoint.profiler.plugin.TypeUtils;
|
||||
import com.navercorp.pinpoint.profiler.plugin.objectfactory.AutoBindingObjectFactory;
|
||||
import com.navercorp.pinpoint.profiler.plugin.transformer.ClassCookBook;
|
||||
import com.navercorp.pinpoint.profiler.plugin.transformer.ClassRecipe;
|
||||
@@ -46,16 +45,16 @@ import com.navercorp.pinpoint.profiler.plugin.transformer.MethodTransformer;
|
||||
|
||||
public class TargetAnnotatedInterceptorInjector implements ClassRecipe {
|
||||
private final DefaultProfilerPluginContext pluginContext;
|
||||
private final String interceptorName;
|
||||
private final String interceptorClassName;
|
||||
private final Object[] providedArguments;
|
||||
|
||||
private final String groupName;
|
||||
private final ExecutionPolicy executionPoint;
|
||||
|
||||
|
||||
public TargetAnnotatedInterceptorInjector(DefaultProfilerPluginContext pluginContext, String interceptorName, Object[] providedArguments, String groupName, ExecutionPolicy executionPoint) {
|
||||
public TargetAnnotatedInterceptorInjector(DefaultProfilerPluginContext pluginContext, String interceptorClassName, Object[] providedArguments, String groupName, ExecutionPolicy executionPoint) {
|
||||
this.pluginContext = pluginContext;
|
||||
this.interceptorName = interceptorName;
|
||||
this.interceptorClassName = interceptorClassName;
|
||||
this.providedArguments = providedArguments;
|
||||
this.groupName = groupName;
|
||||
this.executionPoint = executionPoint;
|
||||
@@ -63,9 +62,9 @@ public class TargetAnnotatedInterceptorInjector implements ClassRecipe {
|
||||
|
||||
@Override
|
||||
public void edit(ClassLoader classLoader, InstrumentClass target) throws Throwable {
|
||||
Class<? extends Interceptor> interceptorType = TypeUtils.loadClass(classLoader, interceptorName);
|
||||
Class<? extends Interceptor> interceptorType = pluginContext.getClassInjector().loadClass(classLoader, interceptorClassName);
|
||||
|
||||
AnnotatedInterceptorInjector injector = new AnnotatedInterceptorInjector(pluginContext, interceptorName, providedArguments, groupName, executionPoint);
|
||||
AnnotatedInterceptorInjector injector = new AnnotatedInterceptorInjector(pluginContext, interceptorClassName, providedArguments, groupName, executionPoint);
|
||||
ClassRecipe recipe = createMethodEditor(classLoader, interceptorType, target, injector);
|
||||
|
||||
recipe.edit(classLoader, target);
|
||||
@@ -106,7 +105,7 @@ public class TargetAnnotatedInterceptorInjector implements ClassRecipe {
|
||||
}
|
||||
|
||||
if (editors.isEmpty()) {
|
||||
throw new PinpointException("No target is specified. At least one of @Targets, @TargetMethod, @TargetConstructor, @TargetFilter must present. interceptor: " + interceptorName);
|
||||
throw new PinpointException("No target is specified. At least one of @Targets, @TargetMethod, @TargetConstructor, @TargetFilter must present. interceptor: " + interceptorClassName);
|
||||
}
|
||||
|
||||
return editors.size() == 1 ? editors.get(0) : new ClassCookBook(editors);
|
||||
@@ -116,7 +115,7 @@ public class TargetAnnotatedInterceptorInjector implements ClassRecipe {
|
||||
String methodName = annotation.name();
|
||||
|
||||
if (methodName == null) {
|
||||
throw new PinpointException("name() of @TargetMethod cannot be null: " + interceptorName);
|
||||
throw new PinpointException("name() of @TargetMethod cannot be null: " + interceptorClassName);
|
||||
}
|
||||
|
||||
String[] parameterTypeNames = annotation.paramTypes();
|
||||
@@ -133,7 +132,7 @@ public class TargetAnnotatedInterceptorInjector implements ClassRecipe {
|
||||
String type = annotation.type();
|
||||
|
||||
if (type == null) {
|
||||
throw new PinpointException("type of @TargetFilter is null: " + interceptorName);
|
||||
throw new PinpointException("type of @TargetFilter is null: " + interceptorClassName);
|
||||
}
|
||||
|
||||
AutoBindingObjectFactory filterFactory = new AutoBindingObjectFactory(pluginContext, targetClass, classLoader);
|
||||
@@ -147,7 +146,7 @@ public class TargetAnnotatedInterceptorInjector implements ClassRecipe {
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("TargetAnnotatedInterceptorInjector [interceptorClass=");
|
||||
builder.append(interceptorName);
|
||||
builder.append(interceptorClassName);
|
||||
|
||||
if (providedArguments != null) {
|
||||
builder.append(", constructorArguments=");
|
||||
|
||||
+6
-5
@@ -26,29 +26,30 @@ import com.navercorp.pinpoint.bootstrap.interceptor.group.InterceptorGroup;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ObjectRecipe;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ObjectRecipe.ByConstructor;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ObjectRecipe.ByStaticFactoryMethod;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginContext;
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
import com.navercorp.pinpoint.profiler.plugin.TypeUtils;
|
||||
import com.navercorp.pinpoint.profiler.plugin.DefaultProfilerPluginContext;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public class AutoBindingObjectFactory {
|
||||
private final DefaultProfilerPluginContext pluginContext;
|
||||
private final ClassLoader classLoader;
|
||||
private final PinpointTypeArgumentProvider pinpointResolver;
|
||||
|
||||
public AutoBindingObjectFactory(ProfilerPluginContext pluginContext, InstrumentClass targetClass, ClassLoader classLoader) {
|
||||
public AutoBindingObjectFactory(DefaultProfilerPluginContext pluginContext, InstrumentClass targetClass, ClassLoader classLoader) {
|
||||
this(pluginContext, null, targetClass, null, classLoader);
|
||||
}
|
||||
|
||||
public AutoBindingObjectFactory(ProfilerPluginContext pluginContext, InterceptorGroup interceptorGroup, InstrumentClass targetClass, MethodInfo targetMethod, ClassLoader classLoader) {
|
||||
public AutoBindingObjectFactory(DefaultProfilerPluginContext pluginContext, InterceptorGroup interceptorGroup, InstrumentClass targetClass, MethodInfo targetMethod, ClassLoader classLoader) {
|
||||
this.pluginContext = pluginContext;
|
||||
this.classLoader = classLoader;
|
||||
this.pinpointResolver = new PinpointTypeArgumentProvider(pluginContext, interceptorGroup, targetClass, targetMethod);
|
||||
}
|
||||
|
||||
public Object createInstance(ObjectRecipe recipe) {
|
||||
Class<?> type = TypeUtils.loadClass(classLoader, recipe.getClassName());
|
||||
Class<?> type = pluginContext.getClassInjector().loadClass(classLoader, recipe.getClassName());
|
||||
ArgumentsResolver argumentsResolver = getParameterResolvers(classLoader, recipe.getArguments());
|
||||
|
||||
if (recipe instanceof ByConstructor) {
|
||||
|
||||
+2
-13
@@ -23,45 +23,34 @@ import com.navercorp.pinpoint.bootstrap.instrument.ByteCodeInstrumentor;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.matcher.Matcher;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.matcher.Matchers;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.PluginClassLoaderFactory;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.transformer.PinpointClassFileTransformer;
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
import com.navercorp.pinpoint.profiler.util.JavaAssistUtils;
|
||||
|
||||
public class DedicatedClassFileTransformer implements PinpointClassFileTransformer {
|
||||
private final ByteCodeInstrumentor instrumentor;
|
||||
private final PluginClassLoaderFactory classLoaderFactory;
|
||||
|
||||
private final String targetClassName;
|
||||
private final ClassRecipe recipe;
|
||||
|
||||
|
||||
public DedicatedClassFileTransformer(ByteCodeInstrumentor instrumentor, PluginClassLoaderFactory classLoaderFactory, String targetClassName, ClassRecipe recipe) {
|
||||
public DedicatedClassFileTransformer(ByteCodeInstrumentor instrumentor, String targetClassName, ClassRecipe recipe) {
|
||||
this.instrumentor = instrumentor;
|
||||
this.classLoaderFactory = classLoaderFactory;
|
||||
|
||||
this.targetClassName = targetClassName;
|
||||
this.recipe = recipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(ClassLoader classLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
|
||||
ClassLoader forPlugin = classLoaderFactory.get(classLoader);
|
||||
|
||||
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(forPlugin);
|
||||
|
||||
try {
|
||||
InstrumentClass target = instrumentor.getClass(classLoader, className, classfileBuffer);
|
||||
recipe.edit(forPlugin, target);
|
||||
recipe.edit(classLoader, target);
|
||||
return target.toBytecode();
|
||||
} catch (PinpointException e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
String msg = "Fail to invoke plugin class recipe: " + toString();
|
||||
throw new PinpointException(msg, e);
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ public class DefaultClassFileTransformerBuilder implements ClassFileTransformerB
|
||||
@Override
|
||||
public PinpointClassFileTransformer build() {
|
||||
ClassRecipe recipe = buildClassRecipe();
|
||||
return new DedicatedClassFileTransformer(pluginContext.getByteCodeInstrumentor(), pluginContext.getClassLoaderFactory(), targetClassName, recipe);
|
||||
return new DedicatedClassFileTransformer(pluginContext.getByteCodeInstrumentor(), targetClassName, recipe);
|
||||
}
|
||||
|
||||
private ClassRecipe buildClassRecipe() {
|
||||
|
||||
@@ -19,25 +19,30 @@ package com.navercorp.pinpoint.test;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.thrift.TBase;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.AgentOption;
|
||||
import com.navercorp.pinpoint.bootstrap.DefaultAgentOption;
|
||||
import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig;
|
||||
import com.navercorp.pinpoint.bootstrap.context.ServerMetaDataHolder;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier.ExpectedAnnotation;
|
||||
import com.navercorp.pinpoint.common.plugin.PluginLoader;
|
||||
import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService;
|
||||
import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService;
|
||||
import com.navercorp.pinpoint.common.trace.ServiceType;
|
||||
|
||||
import org.apache.thrift.TBase;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig;
|
||||
import com.navercorp.pinpoint.bootstrap.context.ServerMetaDataHolder;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier.ExpectedAnnotation;
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
import com.navercorp.pinpoint.profiler.DefaultAgent;
|
||||
import com.navercorp.pinpoint.profiler.context.Span;
|
||||
import com.navercorp.pinpoint.profiler.context.SpanEvent;
|
||||
import com.navercorp.pinpoint.profiler.context.storage.StorageFactory;
|
||||
import com.navercorp.pinpoint.profiler.interceptor.GlobalInterceptorRegistryBinder;
|
||||
import com.navercorp.pinpoint.profiler.plugin.DefaultProfilerPluginContext;
|
||||
import com.navercorp.pinpoint.profiler.plugin.ProfilerPluginClassLoader;
|
||||
import com.navercorp.pinpoint.profiler.receiver.CommandDispatcher;
|
||||
import com.navercorp.pinpoint.profiler.sender.DataSender;
|
||||
import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender;
|
||||
@@ -108,6 +113,25 @@ public class MockAgent extends DefaultAgent {
|
||||
return new ResettableServerMetaDataHolder(vmArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DefaultProfilerPluginContext> loadPlugins(AgentOption agentOption) {
|
||||
List<DefaultProfilerPluginContext> pluginContexts = new ArrayList<DefaultProfilerPluginContext>();
|
||||
ProfilerPluginClassLoader classInjector = new TestProfilerPluginClassLoader();
|
||||
|
||||
List<ProfilerPlugin> plugins = PluginLoader.load(ProfilerPlugin.class, ClassLoader.getSystemClassLoader());
|
||||
|
||||
for (ProfilerPlugin plugin : plugins) {
|
||||
DefaultProfilerPluginContext context = new DefaultProfilerPluginContext(this, classInjector);
|
||||
plugin.setup(context);
|
||||
context.markInitialized();
|
||||
pluginContexts.add(context);
|
||||
}
|
||||
|
||||
|
||||
return pluginContexts;
|
||||
|
||||
}
|
||||
|
||||
public static String toString(Span span) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append('(');
|
||||
|
||||
+15
-20
@@ -1,40 +1,35 @@
|
||||
/*
|
||||
/**
|
||||
* Copyright 2014 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.test;
|
||||
|
||||
package com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
import com.navercorp.pinpoint.profiler.plugin.ProfilerPluginClassLoader;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
* @author emeroad
|
||||
*
|
||||
*/
|
||||
public class Java7PluginClassLoader extends URLClassLoader {
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
public Java7PluginClassLoader(URL[] urls, ClassLoader parent) {
|
||||
super(urls, parent);
|
||||
}
|
||||
public class TestProfilerPluginClassLoader implements ProfilerPluginClassLoader {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
// for debugging
|
||||
return super.loadClass(name, resolve);
|
||||
public <T> Class<? extends T> loadClass(ClassLoader targetClassLoader, String className) {
|
||||
try {
|
||||
return (Class<? extends T>) targetClassLoader.loadClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new PinpointException("Cannot find class: " + className, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-7
@@ -20,8 +20,6 @@ import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -36,6 +34,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.transformer.MethodTransformerBuilder;
|
||||
import com.navercorp.pinpoint.profiler.DefaultAgent;
|
||||
import com.navercorp.pinpoint.profiler.plugin.transformer.DefaultClassFileTransformerBuilder;
|
||||
import com.navercorp.pinpoint.test.TestProfilerPluginClassLoader;
|
||||
|
||||
public class DefaultClassEditorBuilderTest {
|
||||
public static final String SCOPE_NAME = "test";
|
||||
@@ -47,11 +46,9 @@ public class DefaultClassEditorBuilderTest {
|
||||
InstrumentClass aClass = mock(InstrumentClass.class);
|
||||
MethodInfo aMethod = mock(MethodInfo.class);
|
||||
MethodDescriptor aDescriptor = mock(MethodDescriptor.class);
|
||||
DefaultPluginClassLoaderFactory classLoaderFactory = mock(DefaultPluginClassLoaderFactory.class);
|
||||
DefaultAgent agent = mock(DefaultAgent.class);
|
||||
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
ClassLoader childClassLoader = new URLClassLoader(new URL[0], classLoader);
|
||||
String className = "someClass";
|
||||
String methodName = "someMethod";
|
||||
byte[] classFileBuffer = new byte[0];
|
||||
@@ -60,8 +57,6 @@ public class DefaultClassEditorBuilderTest {
|
||||
|
||||
when(agent.getByteCodeInstrumentor()).thenReturn(instrumentor);
|
||||
when(agent.getTraceContext()).thenReturn(traceContext);
|
||||
when(agent.getPluginClassLoaderFactory()).thenReturn(classLoaderFactory);
|
||||
when(classLoaderFactory.get(classLoader)).thenReturn(childClassLoader);
|
||||
when(instrumentor.getClass(classLoader, className, classFileBuffer)).thenReturn(aClass);
|
||||
when(aClass.getDeclaredMethod(methodName, parameterTypeNames)).thenReturn(aMethod);
|
||||
when(aMethod.getName()).thenReturn(methodName);
|
||||
@@ -69,7 +64,8 @@ public class DefaultClassEditorBuilderTest {
|
||||
when(aMethod.getDescriptor()).thenReturn(aDescriptor);
|
||||
when(aClass.addInterceptor(eq(methodName), eq(parameterTypeNames), isA(Interceptor.class))).thenReturn(0);
|
||||
|
||||
DefaultProfilerPluginContext context = new DefaultProfilerPluginContext(agent);
|
||||
DefaultProfilerPluginContext context = new DefaultProfilerPluginContext(agent, new TestProfilerPluginClassLoader());
|
||||
|
||||
DefaultClassFileTransformerBuilder builder = new DefaultClassFileTransformerBuilder(context, "TargetClass");
|
||||
builder.injectMetadata("a", "java.util.HashMap");
|
||||
builder.injectFieldAccessor("someField");
|
||||
|
||||
+2
@@ -37,6 +37,7 @@ import com.navercorp.pinpoint.profiler.plugin.TestInterceptors.TestInterceptor0;
|
||||
import com.navercorp.pinpoint.profiler.plugin.TestInterceptors.TestInterceptor1;
|
||||
import com.navercorp.pinpoint.profiler.plugin.TestInterceptors.TestInterceptor2;
|
||||
import com.navercorp.pinpoint.profiler.plugin.interceptor.AnnotatedInterceptorFactory;
|
||||
import com.navercorp.pinpoint.test.TestProfilerPluginClassLoader;
|
||||
|
||||
public class DefaultInterceptorFactoryTest {
|
||||
private final DefaultProfilerPluginContext pluginContext = mock(DefaultProfilerPluginContext.class);
|
||||
@@ -50,6 +51,7 @@ public class DefaultInterceptorFactoryTest {
|
||||
public void setUp() {
|
||||
reset(instrumentor, traceContext, aClass, aMethod);
|
||||
when(pluginContext.getTraceContext()).thenReturn(traceContext);
|
||||
when(pluginContext.getClassInjector()).thenReturn(new TestProfilerPluginClassLoader());
|
||||
when(aMethod.getDescriptor()).thenReturn(descriptor);
|
||||
}
|
||||
|
||||
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014 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.plugin;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Jongho Moon
|
||||
*
|
||||
*/
|
||||
public class Java6UnsafePluginClassLoaderTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
ClassLoader parent = ClassLoader.getSystemClassLoader();
|
||||
ClassLoader child = new Java6UnsafePluginClassLoader(new URL[0], parent);
|
||||
|
||||
final int run = 10000;
|
||||
final int threadNum = 16;
|
||||
Thread[] thread = new Thread[threadNum];
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
if (i % 2 == 0) {
|
||||
thread[i] = new Thread(new Parent(parent, child, run));
|
||||
} else {
|
||||
thread[i] = new Thread(new Child(child, run));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
thread[i].start();
|
||||
}
|
||||
|
||||
System.out.println("Wait workers...");
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
thread[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class Parent implements Runnable {
|
||||
private final ClassLoader parent;
|
||||
private final ClassLoader child;
|
||||
private final int count;
|
||||
|
||||
public Parent(ClassLoader parent, ClassLoader child, int count) {
|
||||
this.parent = parent;
|
||||
this.child = child;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
synchronized(parent) {
|
||||
try {
|
||||
child.loadClass("no.such.Class");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Child implements Runnable {
|
||||
private final ClassLoader child;
|
||||
private final int count;
|
||||
|
||||
public Child(ClassLoader child, int count) {
|
||||
this.child = child;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
synchronized(child) {
|
||||
try {
|
||||
child.loadClass("no.such.Class");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user