Browse Source

Fix possible deadlock (#5585)

* Fix possible deadlock

* don't break java 8

* try @laurit's idea

* Update javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/AgentClassLoader.java

Co-authored-by: Lauri Tulmin <tulmin@gmail.com>

Co-authored-by: Lauri Tulmin <tulmin@gmail.com>
Trask Stalnaker 3 years ago
parent
commit
531f18f56b

+ 41 - 24
javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/AgentClassLoader.java

@@ -117,34 +117,11 @@ public class AgentClassLoader extends URLClassLoader {
 
   private static ClassLoader getParentClassLoader() {
     if (JAVA_VERSION > 8) {
-      ClassLoader platformClassLoader = getPlatformLoader();
-      return new ClassLoader(null) {
-        @Override
-        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
-          // prometheus exporter uses jdk http server, load it from the platform class loader
-          if (name != null && name.startsWith("com.sun.net.httpserver.")) {
-            return platformClassLoader.loadClass(name);
-          }
-          return super.loadClass(name, resolve);
-        }
-      };
+      return new JdkHttpServerClassLoader();
     }
     return null;
   }
 
-  private static ClassLoader getPlatformLoader() {
-    /*
-     Must invoke ClassLoader.getPlatformClassLoader by reflection to remain
-     compatible with java 8.
-    */
-    try {
-      Method method = ClassLoader.class.getDeclaredMethod("getPlatformClassLoader");
-      return (ClassLoader) method.invoke(null);
-    } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException exception) {
-      throw new IllegalStateException(exception);
-    }
-  }
-
   private static int getJavaVersion() {
     String javaSpecVersion = System.getProperty("java.specification.version");
     if ("1.8".equals(javaSpecVersion)) {
@@ -451,4 +428,44 @@ public class AgentClassLoader extends URLClassLoader {
       return -1;
     }
   }
+
+  private static class JdkHttpServerClassLoader extends ClassLoader {
+
+    static {
+      // this class loader doesn't load any classes, so this is technically unnecessary,
+      // but included for safety, just in case we every change Class.forName() below back to
+      // super.loadClass()
+      registerAsParallelCapable();
+    }
+
+    private final ClassLoader platformClassLoader = getPlatformLoader();
+
+    public JdkHttpServerClassLoader() {
+      super(null);
+    }
+
+    @Override
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+      // prometheus exporter uses jdk http server, load it from the platform class loader
+      if (name != null && name.startsWith("com.sun.net.httpserver.")) {
+        return platformClassLoader.loadClass(name);
+      }
+      return Class.forName(name, false, null);
+    }
+
+    private static ClassLoader getPlatformLoader() {
+      /*
+       Must invoke ClassLoader.getPlatformClassLoader by reflection to remain
+       compatible with java 8.
+      */
+      try {
+        Method method = ClassLoader.class.getDeclaredMethod("getPlatformClassLoader");
+        return (ClassLoader) method.invoke(null);
+      } catch (InvocationTargetException
+          | NoSuchMethodException
+          | IllegalAccessException exception) {
+        throw new IllegalStateException(exception);
+      }
+    }
+  }
 }