image.png

1 ContainerClassLoader

com.alipay.sofa.ark.bootstrap.ContainerClassLoader 直接继承URLClassLoader

2 PluginClassLoader

com.alipay.sofa.ark.container.service.classloader.PluginClassLoader

  1. // 0. sun reflect related class throw exception directly
  2. if (classloaderService.isSunReflectClass(name)) {
  3. throw new ArkLoaderException(
  4. String
  5. .format(
  6. "[ArkPlugin Loader] %s : can not load class: %s, this class can only be loaded by sun.reflect.DelegatingClassLoader",
  7. pluginName, name));
  8. }
  9. // 1. findLoadedClass
  10. if (clazz == null) {
  11. clazz = findLoadedClass(name);
  12. }
  13. // 2. JDK related class
  14. if (clazz == null) {
  15. clazz = resolveJDKClass(name);
  16. }
  17. // 3. Ark Spi class
  18. if (clazz == null) {
  19. clazz = resolveArkClass(name);
  20. }
  21. // 4. pre find class
  22. if (clazz == null) {
  23. clazz = preLoadClass(name);
  24. }
  25. // 5. Import class export by other plugins
  26. if (clazz == null) {
  27. clazz = resolveExportClass(name);
  28. }
  29. // 6. Plugin classpath class
  30. if (clazz == null) {
  31. clazz = resolveLocalClass(name);
  32. }
  33. // 7. Java Agent ClassLoader for agent problem
  34. if (clazz == null) {
  35. clazz = resolveJavaAgentClass(name);
  36. }
  37. // 8. Post find class
  38. if (clazz == null) {
  39. clazz = postLoadClass(name);
  40. }
  41. if (clazz != null) {
  42. if (resolve) {
  43. super.resolveClass(clazz);
  44. }
  45. return clazz;
  46. }
  47. throw new ArkLoaderException(String.format(
  48. "[ArkPlugin Loader] %s : can not load class: %s", pluginName, name));

每个 Ark 插件都拥有一个独立的类加载器,其类加载的顺序如下:
1 如果是加载反射生成的字节码,那么会直接抛出 ClassNotFoundException,终止类加载。这一部分主要是来源于我们的工程实践,避免一定找不到的类查找路径过长
2 查找已经被加载过的类
查找 JDK 中的类,这一块主要包含两部分:第一部分是 ExtClassloader 负责加载的类;第二部分是 JDK 提供的类但从 ExtClassloader 中加载不到,但在本地运行时会被加入到 SystemClassloader 的 classpath 中,同时这些类可能会被放到一些三方工具包中,典型的如 tool.jar 中 sun.tools.attach.BsdVirtualMachine,这一部分也主要来源于我们的工程实践,避免类被加载超过一次,从而引发报错
3 看类是否是由 Sofa Ark 提供的接口类,典型的如: com.alipay.sofa.ark.spi.service.PluginActivator, 如果是,则类会委托给 Ark 容器的类加载器加载
4 看是否在插件的 import 中(包括 import-classes 和 import-package), 如果在,则会委托给导出该类的插件类加载器加载在插件自身的 classpath 中加载
如果上述都失败了,则会尝试在 SymtemClassloader 中加载,这一步主要是为了解决使用 agent 时的情形

3 BizClassLoader

com.alipay.sofa.ark.container.service.classloader.BizClassLoader:

  1. // 0. sun reflect related class throw exception directly
  2. if (classloaderService.isSunReflectClass(name)) {
  3. throw new ArkLoaderException(
  4. String
  5. .format(
  6. "[ArkBiz Loader] %s : can not load class: %s, this class can only be loaded by sun.reflect.DelegatingClassLoader",
  7. bizIdentity, name));
  8. }
  9. // 1. findLoadedClass
  10. if (clazz == null) {
  11. clazz = findLoadedClass(name);
  12. }
  13. // 2. JDK related class
  14. if (clazz == null) {
  15. clazz = resolveJDKClass(name);
  16. }
  17. // 3. Ark Spi class
  18. if (clazz == null) {
  19. clazz = resolveArkClass(name);
  20. }
  21. // 4. pre find class
  22. if (clazz == null) {
  23. clazz = preLoadClass(name);
  24. }
  25. // 5. Plugin Export class
  26. if (clazz == null) {
  27. clazz = resolveExportClass(name);
  28. }
  29. // 6. Biz classpath class
  30. if (clazz == null) {
  31. clazz = resolveLocalClass(name);
  32. }
  33. // 7. Java Agent ClassLoader for agent problem
  34. if (clazz == null) {
  35. clazz = resolveJavaAgentClass(name);
  36. }
  37. // 8. post find class
  38. if (clazz == null) {
  39. clazz = postLoadClass(name);
  40. }
  41. if (clazz != null) {
  42. if (resolve) {
  43. super.resolveClass(clazz);
  44. }
  45. return clazz;
  46. }
  47. throw new ArkLoaderException(String.format("[ArkBiz Loader] %s : can not load class: %s",
  48. bizIdentity, name));

下步骤搜索:

  1. 如果已加载过,那就返回已加载好的那个类。
  2. 如果这个类是JDK自己的,那么就用JDKClassLoader去加载。
  3. 如果这个类是属于Ark容器的,那么就用ArkClassLoader去加载。
  4. 如果这个类是某个插件export的,那么就用ExportClassLoader去加载。
  5. 如果这个类是我业务自己的,那么就用当前的ClassLoader直接loadClass就好。
  6. 否则就去试试是不是用了某个java agent。
  7. 再找不到就报错。