• Skywalking流程分析_2(配置加载和自定义类加载器初始化)


    读取配置

    SnifferConfigInitializer.initializeCoreConfig(agentArgs)这个方法就是读取配置文件agent.config的文件就是在此方法中读取的

    public static void initializeCoreConfig(String agentOptions) {
        //开始进行加载配置信息 优先级(数字越小优先级越大) 1:启动命令的age
        nt参数  2:系统环境变量 3:agent.config的配置
        AGENT_SETTINGS = new Properties();
        //读取配置文件
        try (final InputStreamReader configFileStream = loadConfig()) {
            AGENT_SETTINGS.load(configFileStream);
            for (String key : AGENT_SETTINGS.stringPropertyNames()) {
                String value = (String) AGENT_SETTINGS.get(key);
                //配置项占位符替换
                AGENT_SETTINGS.put(key, PropertyPlaceholderHelper.INSTANCE.replacePlaceholders(value, AGENT_SETTINGS));
            }
    
        } catch (Exception e) {
            LOGGER.error(e, "Failed to read the config file, skywalking is going to run in default config.");
        }
    
        try {
            //如果配置环境变量则进行替换
            overrideConfigBySystemProp();
        } catch (Exception e) {
            LOGGER.error(e, "Failed to read the system properties.");
        }
    
        agentOptions = StringUtil.trim(agentOptions, ',');
        if (!StringUtil.isEmpty(agentOptions)) {
            try {
                agentOptions = agentOptions.trim();
                LOGGER.info("Agent options is {}.", agentOptions);
                //用agent的配置文件进行替换
                overrideConfigByAgentOptions(agentOptions);
            } catch (Exception e) {
                LOGGER.error(e, "Failed to parse the agent options, val is {}.", agentOptions);
            }
        }
        //将配置信息映射到Config类中
        initializeConfig(Config.class);
        // reconfigure logger after config initialization
        //根据配置信息配置日志
        configureLogger();
        LOGGER = LogManager.getLogger(SnifferConfigInitializer.class);
    
        setAgentVersion();
    
        // 检查名称和地址是否进行设置
        if (StringUtil.isEmpty(Config.Agent.SERVICE_NAME)) {
            throw new ExceptionInInitializerError("`agent.service_name` is missing.");
        } else {
            if (StringUtil.isNotEmpty(Config.Agent.NAMESPACE) || StringUtil.isNotEmpty(Config.Agent.CLUSTER)) {
                Config.Agent.SERVICE_NAME = StringUtil.join(
                    SERVICE_NAME_PART_CONNECTOR,
                    Config.Agent.SERVICE_NAME,
                    Config.Agent.NAMESPACE,
                    Config.Agent.CLUSTER
                );
            }
        }
        if (StringUtil.isEmpty(Config.Collector.BACKEND_SERVICE)) {
            throw new ExceptionInInitializerError("`collector.backend_service` is missing.");
        }
        if (Config.Plugin.PEER_MAX_LENGTH <= 3) {
            LOGGER.warn(
                "PEER_MAX_LENGTH configuration:{} error, the default value of 200 will be used.",
                Config.Plugin.PEER_MAX_LENGTH
            );
            Config.Plugin.PEER_MAX_LENGTH = 200;
        }
        //初始化完成标识符
        IS_INIT_COMPLETED = true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    总结

    • 按照优先级将配置读取到AGENT_SETTINGS
    • AGENT_SETTINGS加载到Config类中
    • IS_INIT_COMPLETED初始化完成标识符设置为true

    加载插件以及初始化自定义AgentClassLoader类加载器

    pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
    首先分析new PluginBootstrap().loadPlugins()这个方法非常的重要,进行自定义AgentClassLoader类加载器的初始化

    new PluginBootstrap().loadPlugins()

    public List<AbstractClassEnhancePluginDefine> loadPlugins() throws AgentPackageNotFoundException {
        //自定义AgentClassLoader类加载器
        AgentClassLoader.initDefaultLoader();
        //获取所有的skywalking-plugin.def的文件
        PluginResourcesResolver resolver = new PluginResourcesResolver();
        List<URL> resources = resolver.getResources();
    
        if (resources == null || resources.size() == 0) {
            LOGGER.info("no plugin files (skywalking-plugin.def) found, continue to start application.");
            return new ArrayList<AbstractClassEnhancePluginDefine>();
        }
        
        for (URL pluginUrl : resources) {
            try {
                //读取skywalking-plugin.def中的指定插件配置
                PluginCfg.INSTANCE.load(pluginUrl.openStream());
            } catch (Throwable t) {
                LOGGER.error(t, "plugin file [{}] init failure.", pluginUrl);
            }
        }
    
        List<PluginDefine> pluginClassList = PluginCfg.INSTANCE.getPluginClassList();
    
        List<AbstractClassEnhancePluginDefine> plugins = new ArrayList<AbstractClassEnhancePluginDefine>();
        for (PluginDefine pluginDefine : pluginClassList) {
            try {
                LOGGER.debug("loading plugin class {}.", pluginDefine.getDefineClass());
                //类加载器加载plugin的插件
                AbstractClassEnhancePluginDefine plugin = (AbstractClassEnhancePluginDefine) Class.forName(pluginDefine.getDefineClass(), true, AgentClassLoader
                    .getDefault()).newInstance();
                plugins.add(plugin);
            } catch (Throwable t) {
                LOGGER.error(t, "load plugin [{}] failure.", pluginDefine.getDefineClass());
            }
        }
        //加载基于xml定义的插件
        plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
    
        return plugins;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    自定义AgentClassLoader类加载器

    AgentClassLoader.initDefaultLoader()

    public class AgentClassLoader extends ClassLoader {
      static {
          /*
           * Try to solve the classloader dead lock. See https://github.com/apache/skywalking/pull/2016
           * 
           * 注册并行能力并发类加载器
           */
          registerAsParallelCapable();
      }
      /**
       * 初始化AgentClassLoader类加载器
       * */
      public static void initDefaultLoader() throws AgentPackageNotFoundException {
          if (DEFAULT_LOADER == null) {
              synchronized (AgentClassLoader.class) {
                  if (DEFAULT_LOADER == null) {
                      DEFAULT_LOADER = new AgentClassLoader(PluginBootstrap.class.getClassLoader());
                  }
              }
          }
      }
    
      public AgentClassLoader(ClassLoader parent) throws AgentPackageNotFoundException {
          super(parent);
          //jar包所在的目录
          File agentDictionary = AgentPackagePath.getPath();
          classpath = new LinkedList<>();
          //加载plugins, activations目录下的插件
          //public static List MOUNT = Arrays.asList("plugins", "activations");
          Config.Plugin.MOUNT.forEach(mountFolder -> classpath.add(new File(agentDictionary, mountFolder)));
      }
    //省略
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    总结

    • registerAsParallelCapable()是为了解决ClassLoader死锁问题,并开启类加载器的并行加载模式。

      • jdk1.7之前,类加载器在加载类是串行加载的,加载完上一个再加载下一个,效率低下
      • JDK1.7之后,提供了类加载器并行能力,就是把锁的粒度变小,之前ClassLoader加载类的时候加锁的时候是用自身作为锁的,现在优化成为锁在具体的某一个类上,而不是锁在整个类加载器
    • AgentClassLoader重写了findClass、findResource、findResources方法,将从plugins, activations目录读取到的插件集合classpath进行加载

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<Jar> allJars = getAllJars();
        String path = name.replace('.', '/').concat(".class");
        for (Jar jar : allJars) {
            JarEntry entry = jar.jarFile.getJarEntry(path);
            if (entry == null) {
                continue;
            }
            try {
                URL classFileUrl = new URL("jar:file:" + jar.sourceFile.getAbsolutePath() + "!/" + path);
                byte[] data;
                try (final BufferedInputStream is = new BufferedInputStream(
                    classFileUrl.openStream()); final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                    int ch;
                    while ((ch = is.read()) != -1) {
                        baos.write(ch);
                    }
                    data = baos.toByteArray();
                }
                //读取带有PluginConfig注解的配置
                return processLoadedClass(defineClass(name, data, 0, data.length));
            } catch (IOException e) {
                LOGGER.error(e, "find class fail.");
            }
        }
        throw new ClassNotFoundException("Can't find " + name);
    }
    
    @Override
    protected URL findResource(String name) {
        List<Jar> allJars = getAllJars();
        for (Jar jar : allJars) {
            JarEntry entry = jar.jarFile.getJarEntry(name);
            if (entry != null) {
                try {
                    return new URL("jar:file:" + jar.sourceFile.getAbsolutePath() + "!/" + name);
                } catch (MalformedURLException ignored) {
                }
            }
        }
        return null;
    }
    
    @Override
    protected Enumeration<URL> findResources(String name) throws IOException {
        List<URL> allResources = new LinkedList<>();
        List<Jar> allJars = getAllJars();
        for (Jar jar : allJars) {
            JarEntry entry = jar.jarFile.getJarEntry(name);
            if (entry != null) {
                allResources.add(new URL("jar:file:" + jar.sourceFile.getAbsolutePath() + "!/" + name));
            }
        }
    
        final Iterator<URL> iterator = allResources.iterator();
        return new Enumeration<URL>() {
            @Override
            public boolean hasMoreElements() {
                return iterator.hasNext();
            }
    
            @Override
            public URL nextElement() {
                return iterator.next();
            }
        };
    }
    
    private Class<?> processLoadedClass(Class<?> loadedClass) {
        final PluginConfig pluginConfig = loadedClass.getAnnotation(PluginConfig.class);
        if (pluginConfig != null) {
            // Set up the plugin config when loaded by class loader at the first time.
            // Agent class loader just loaded limited classes in the plugin jar(s), so the cost of this
            // isAssignableFrom would be also very limited.
            SnifferConfigInitializer.initializeConfig(pluginConfig.root());
        }
    
        return loadedClass;
    }
    
    private List<Jar> getAllJars() {
        if (allJars == null) {
            jarScanLock.lock();
            try {
                if (allJars == null) {
                    allJars = doGetJars();
                }
            } finally {
                jarScanLock.unlock();
            }
        }
    
        return allJars;
    }
    
    private LinkedList<Jar> doGetJars() {
        LinkedList<Jar> jars = new LinkedList<>();
        //classpath就是刚才加载出来的插件集合
        for (File path : classpath) {
            if (path.exists() && path.isDirectory()) {
                String[] jarFileNames = path.list((dir, name) -> name.endsWith(".jar"));
                for (String fileName : jarFileNames) {
                    try {
                        File file = new File(path, fileName);
                        Jar jar = new Jar(new JarFile(file), file);
                        jars.add(jar);
                        LOGGER.info("{} loaded.", file.toString());
                    } catch (IOException e) {
                        LOGGER.error(e, "{} jar file can't be resolved", fileName);
                    }
                }
            }
        }
        return jars;
    }
    
    @RequiredArgsConstructor
    private static class Jar {
        private final JarFile jarFile;
        private final File sourceFile;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122

    获取所有的skywalking-plugin.def的文件

    List resources = resolver.getResources()

    public List<URL> getResources() {
        List<URL> cfgUrlPaths = new ArrayList<URL>();
        Enumeration<URL> urls;
        try {
            urls = AgentClassLoader.getDefault().getResources("skywalking-plugin.def");
    
            while (urls.hasMoreElements()) {
                URL pluginUrl = urls.nextElement();
                cfgUrlPaths.add(pluginUrl);
                LOGGER.info("find skywalking plugin define in {}", pluginUrl);
            }
    
            return cfgUrlPaths;
        } catch (IOException e) {
            LOGGER.error("read resources failure.", e);
        }
        return null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    使用AgentClassLoader类加载器获取到plugins, activations目录下的所有skywalking-plugin.def的插件

    读取skywalking-plugin.def转换成PluginDefine

    PluginCfg.INSTANCE.load(pluginUrl.openStream())

    void load(InputStream input) throws IOException {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            String pluginDefine;
            while ((pluginDefine = reader.readLine()) != null) {
                try {
                    if (pluginDefine.trim().length() == 0 || pluginDefine.startsWith("#")) {
                        continue;
                    }
                    //将一个个插件转成PluginDefine
                    PluginDefine plugin = PluginDefine.build(pluginDefine);
                    pluginClassList.add(plugin);
                } catch (IllegalPluginDefineException e) {
                    LOGGER.error(e, "Failed to format plugin({}) define.", pluginDefine);
                }
            }
            //排除配置文件中不需要启用的插件
            pluginClassList = pluginSelector.select(pluginClassList);
        } finally {
            input.close();
        }
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    还记得最开始的方法pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());吗?AgentClassLoader累加器的初始化、插件的加载生成都是在ew PluginBootstrap().loadPlugins()执行的

    下面分析pluginFinder = new PluginFinder

    pluginFinder = new PluginFinder

    /**
     * Map的泛型为的原因是对于同一个类,可能会有多个插件都要对这个类进行字节码增加
     * 
     * key -> 目标类
     * value -> 所有可以对这个目标类生效的插件
     * */
    private final Map<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();
    private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
    private final List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
    private static boolean IS_PLUGIN_INIT_COMPLETED = false;
    
    /**
     * 将插件进行分类
     *  命名插件、间接匹配插件、jdk类库插件
     * */
    public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
        for (AbstractClassEnhancePluginDefine plugin : plugins) {
            ClassMatch match = plugin.enhanceClass();
    
            if (match == null) {
                continue;
            }
    
            if (match instanceof NameMatch) {
                NameMatch nameMatch = (NameMatch) match;
                LinkedList<AbstractClassEnhancePluginDefine> pluginDefines = nameMatchDefine.get(nameMatch.getClassName());
                if (pluginDefines == null) {
                    pluginDefines = new LinkedList<AbstractClassEnhancePluginDefine>();
                    nameMatchDefine.put(nameMatch.getClassName(), pluginDefines);
                }
                pluginDefines.add(plugin);
            } else {
                signatureMatchDefine.add(plugin);
            }
    
            if (plugin.isBootstrapInstrumentation()) {
                bootstrapClassMatchDefine.add(plugin);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    总结

    • PluginBootstrap实例化所有插件
      • PluginResourcesResolver加载skywalking-plugin.def的文件
      • PluginCfg封装PluginDefine
      • DynamicPluginLoader加载基于xml配置的插件
    • PluginFinder分类插件
      • NameMatch,命名插件
      • IndirectMatch,间接匹配插件
      • JDK类库插件

    以上就是将读取配置文件、自定义类加载器、加载插件的流程分析完毕

  • 相关阅读:
    Apollo:前端开发者的全栈探索之旅
    golang八股文整理(持续搬运)
    【Linux】感性认识冯诺依曼体系结构和操作系统
    qt——窗口置灰不可操作
    嵌入式开发:包含远程更新引导加载程序——5个理由
    (附源码)springboot高校宿舍交电费系统 毕业设计031552
    Super Resolve Dynamic Scene from Continuous Spike Streams论文笔记
    C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)
    智慧配电房监控系统的技术研究
    FPGA实现HDMI输入转SDI视频输出,提供4套工程源码和技术支持
  • 原文地址:https://blog.csdn.net/guntun8987/article/details/134380269