一文探索【skywalking】如何通过agent实现启动流程

概述

本文的主角是一款十分著名且运用的链路追寻东西:SkyWalking

SkyWalking是一个APM(application performance monitor)体优先级调度算法系,专门为微服务监控安装、云原生和基于容器(Docker、Kubernetes、Mesos监控眼)的架构而规划,包含了云原生架构下的分布式体系的监控、盯梢、确诊功用。

经过agent的办法,可以做到监控拍下东航客机坠落瞬间对代码无侵入式的介入,实时完结整个服务链路的监控。本文的将架构工程师要介绍的重点是SkyWalking怎么经过agent完结如此全面的监控功用。这儿提到优先级是什么意思的agent是在java中运用的ag优先级是什么意思ent技能,本文所讲的内容也是依托于java为基础的。

一、什么是agent?

1.1 静态agent

1.1.1 简介

JDK从1优先级是什么意思.5开端,引进了agent机制,用户可以经过-javaagent参数运用agent技能。agent技能可以使JVM在加载class文件监控家用远程手机之前先加载agent文件监控拍下东航客机坠落瞬间,经过修正JVM传入的字节码来完结自界说代码的注入。

为什么称之为静态agent实例化servlet类异常?由于运用此种办实例化法,不需求经过指定VM参数的办法,所以想要修正agent有必要要对服务进行重启。

1.1优先级排序c语言.2 运用

下面咱们动手完结一个简略的接口类型静态agent。

1.1.2.1 装备

完结类的实例化静态agent需求装备agent的发动类接口crc错误计数,用来发现办法premain,这是完结静态agent的发动办法,由于是在jvm加载类之前,所以叫做pre-agent

静态agent通常有两种办法:

  • M架构师证书ANIFEST.MF 文件架构图怎么制作

    需求在resources下创立META-INF实例化和初始化的区别文件夹,在监控摄像头内部创立MANIFEST.MF文件,其格局如下(留意最终一行要换行,不然idea或报错):

    Manifest-Version: 1.0
    Premain-Class: com.wjbgn.warriors.agent.StaticAgentTest
    Can-Redefine-Classes: true
    Can-Retransform-Classes: true
    

    除此之外,还需求引进maven-assembly-监控系统plugin插件,不然MANIFEST.MF文件的内容会被maven打包后的内容掩盖掉。

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
            <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
            </descriptorRefs>
            <archive>
                <manifestFile>
                    src/main/resources/META-INF/MANIFEST.MF
                </manifestFile>
            </archive>
        </configuration>
    </plugin>
    
  • 【推荐】引进编译插件 maven-assembly-plugin

    直接运用maven-assembly-plugin插件就能到达运用agent的作用,所以推荐此办法。

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
            <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
            </descriptorRefs>
            <archive>
                <manifestEntries>
                    <Premain-Class>com.wjbgn.warriors.agent.StaticAgentTest</Premain-Class>
                    <Can-Redefine-Classes>true</Can-Redefine-Classes>
                    <Can-Retransform-Classes>true</Can-Retransform-Classes>
                </manifestEntries>
            </archive>
        </configuration>
    </plugin>
    

1.1.2.2 测验

  • 创立一个测验类:

    package com.wjbgn.warriors.agent;
    import java.lang.instrument.Instrumentation;
    /**
     * @description: 静态agent测验类
     * @author:weirx
     * @date:2022/6/30 15:13
     * @version:3.0
     */
    public class StaticAgentTest {
        /**
         * description: 静态agent发动类
         * @param agentArgs
         * @param inst
         * @return: void
         * @author: weirx
         * @time: 2022/6/30 15:14
         */
        public static void premain(String agentArgs, Instrumentation inst) {
            // 在springboot发动前打印一下文字
            System.out.println("this is static agent");
            // 打印vm参数装备的agent参数
            System.out.println(agentArgs);
        }
    }
    
  • 运用assem实例化是什么意思bly插件打包,在idea中:

    一文探究【skywalking】怎么经过agent完结发动流程

    当然也可以运用指令:mvn assembly:single

    打包后文件在项目的target下。

  • 在i实例化servlet类异常dea增加发动参数:

    一文探究【skywalking】怎么经过agent完结发动流程

    蓝色部分是携带的参数,其余部分指定agent的jar包方位,完整架构师工资指令如类的实例化下:

    -javaagent:E:workspacewarriorswarriors-agenttargetwarriors-agent-0.0.1-SNAPSHOT-jar-with-dependencies.jar=[testAgnet]
    
  • 发动项目

    一文探究【skywalking】怎么经过agent完结发动流程

    如上所示,成功输出咱们预期内容。

1.2 动态优先级c语言agent

1.2接口文档.1 简介

JDK在1.6版别开监控端,又引进了attach办法,对于运转中的应用程序,可以对其附加agent,接口卡这一操接口是什么作让接口卡咱们可以动态的修正现已加载的类。这也是称之为动态agent的原因。

经过VirtualMachineattach(pid)可以获得Virt接口ualMachine实例,之后经过loadAgent(agent path)办法将指定的agent加载到正在运转的JVM傍边,完架构图结动态加载。

1.2.2 运用

1.2.2.1 装备

接口卡要运用VirtualMachine,需求引进对应的依靠:

<dependency>
    <groupId>com.sun</groupId>
    <artifactId>tools</artifactId>
    <version>1.8</version>
    <scope>system</scope>
    <systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>

修正装备文件:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
            <manifestEntries>
                <Agent-Class>com.wjbgn.warriors.agent.DynamicAgentTest</Agent-Class>
                <Can-Redefine-Classes>true</Can-Redefine-Classes>
                <Can-Retransform-Classes>true</Can-Retransform-Classes>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

1.2.2.2 预备测验环境

咱们静态ag接口自动化ent工程发动,监控家用远程手机保持在运转中:

一文探究【skywalking】怎么经过agent完结发动流程

检查其进程id:

E:workspacewarriors>jps
15248 Launcher
6480 Jps
13764 RemoteMavenServer36
4532 WarriorsAgentApplication
9188

WarriorsAgentApplication的进程接口类型id是4532

1.2.2.3 测验

  • 创立测验类

    package com.wjbgn.warriors.agent;
    import com.sun.tools.attach.AgentInitializationException;
    import com.sun.tools.attach.AgentLoadException;
    import com.sun.tools.attach.AttachNotSupportedException;
    import com.sun.tools.attach.VirtualMachine;
    import java.io.IOException;
    import java.lang.instrument.Instrumentation;
    /**
     * @description: 动态agent测验
     * @author:weirx
     * @date:2022/6/30 15:53
     * @version:3.0
     */
    public class DynamicAgentTest {
        /**
         * description: 动态agent,经过attach和loadAgent进行探针载入
         *
         * @param agentArgs
         * @param inst
         * @return: void
         * @author: weirx
         * @time: 2022/6/30 15:54
         */
        public static void agentmain(String agentArgs, Instrumentation inst) {
            // 打印以下日志
            System.out.println("this is static agent");
            // 打印参数
            System.out.println(agentArgs);
        }
        public static void main(String[] args) {
            VirtualMachine virtualMachine = null;
            try {
                // 指定进程号
                virtualMachine = VirtualMachine.attach("4532");
                // 指定agent jar包路径和参数
                virtualMachine.loadAgent("E:workspacewarriorswarriors-agenttargetwarriors-agent-0.0.1-SNAPSHOT-jar-with-dependencies.jar", "agentTest");
            } catch (AttachNotSupportedException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (AgentLoadException e) {
                e.printStackTrace();
            } catch (AgentInitializationException e) {
                e.printStackTrace();
            }
        }
    }
    

    如上所示,包含两部分:

    • agen实例化对象是什么意思tmain 发动程序
    • ma接口测试用例设计in办法履行attach和loadAgent办法,加载agent到当时指定进程id的架构师证书应用程序中。
  • 运用assembly插件打包,在idea中:

    一文探究【skywalking】怎么经过agent完结发动流程

    当然也可以运优先级队列用指令:mvn assembly:single

    打包后文件在项目的target下。

  • 发动程序

运转上面的main办法,检查正在运转的架构师证书4532项目的控制台:

一文探究【skywalking】怎么经过agent完结发动流程

如上所示,现已输出了实例化servlet类异常动态注入的内容。优先级c语言

1.监控眼3 Instrumentat监控app下载ion

无论是静态agent,仍优先级是动态,咱们发现在其对应的办法傍边,都有一个Instrumentation的入参,那么它是做什么的呢?

运用 Instrumentation,开发者可以构建监控一个独立于应用程序的署理优先级排序c语言程序(Agent),用来监测和帮忙运转在 JVM 上的程序,甚至可以替换和修正某些类的界说。有了这样的功用,开发者就可以完结更为灵敏的运转时虚拟机监控和 Java 类操作了,这样的特性实践上供给了一种虚拟机等级支撑的 AOP 完结办法,使得开发者无需对 JD接口卡K 做任何晋级和改动,就可以完结某些 AOP 的功用了。

更多介绍参考:Java Instrumentation

1.4 小结

关于静态agent动态agent的简略介绍以及运用办法就介绍这么多,当然还有许多细节和有用的方面没有涉及,可是本节的重点意义在于让大家了解a优先级表gent的工作办法,便利咱们后边优先级队列学习skywalking的监控摄像头品牌排行agent完结。源码阅览过程中会针对涉实例化是什么意思及到的agent技能进行解说。

二、Sky监控家用远程手机Walking源码剖析

前面花费大量的华章来解释什么是agent优先级越小越优先吗,从本节开端,正式进接口英文架构工程师源码阅览阶段。

需求单独阐明的

  • 假如你是用的是8.7.0之前的版别,skywalking的服务端和agent的代码是放在同一个项目工优先级英文程skywalking下的。

  • 假如运用8.7.0之后的版别,agent的优先级排序c语言相关代码被抽离出skywalking傍边,不同的言语会对应不同的agent,需求依据需求去自行挑选,比如java运用skywalking-java

  • 在开端学习源码前,建议依照上面的阐明供给的地址拷贝一份源码到本地,有利于对源码的学习。

skywa架构师工资lking是优先级c语言采用静态agent的办法,所以咱们首先要找到它的agent发动类SkyWalkingAg优先级英文ent.java的方位:

一文探究【skywalking】怎么经过agent完结发动流程

2.1 pr架构图怎么画emain 办法

咱们从上至下剖析下监控眼premain的逻辑,只看关键代码方位:

2.1.监控摄像头1 加载插件

2.1.1.1 界说插件寻觅器

 // 界说一个插件寻觅器 
final PluginFinder pluginFinder;

2.1.1.2 加载装备

   // 初始化指定参数,咱们发动项目时分,可以指定服务的称号等参数,内部还加载装备文件agent.config的内容 
   SnifferConfigInitializer.initializeCoreConfig(agentArgs);

运用过skywalking的都知道,咱们有两种装备被监控你服接口和抽象类的区别务的办法:

  • vm参数指定
  • agent.conf 装备

不管架构师证书何种办法,都会经过此行代码进行加载。监控家用远程手机

2.1.1.3 加载插件

    //初始化插件寻觅器 
    //运用PluginResourcesResolver加载并界说一切插件 
    pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());

new PluginBootstrap().loadPlugins()办法内部运用PluginResourcesResolver加载一切的组件,而且要求组件有必要界说在文件skywalking-plugin.def傍边:

一文探究【skywalking】怎么经过agent完结发动流程

如上接口卡图所示,咱们常用的组件都会有其对应的插件界说在这个工程中,需求加载的类都会经过skywalking-plugin.def进行装备,该文件格局如下所示:

一文探究【skywalking】怎么经过agent完结发动流程

new PluginBootstrap().loadPlugins()加载插件的流程如下:

一文探究【skywalking】怎么经过agent完结发动流程

上图流程简介如下:

  • 初始化Pl优先级英文uginBootstrap调用其loadPlugins(监控app下载)
  • loadPlugins办法内部初始化PluginResourcesResolver,并调用其getResources()
  • getResource办法内部运用AgentClassLoadergetResources("s架构师k实例化对象是什么意思ywalking-plugin.def")办法获取一切插件下的s监控眼kywalking-plugin.def文件。
  • AgentClassLoader的底层实践是ClassLoader,运用它的依据文件称号获取文件办法getResources(String name),得到Enumeration<URL>调集,经过遍历获取List<URL>
  • 遍历List<URL实例化>,经过Plug监控家用远程手机inCfg.INSTANCE.load加载插件。
    • 经过pluginDefine = reader.readLine()逐行读取内容
    • 经过PluginDefine.build(pluginDefine)构建读取到的内容
    • 实践bui监控拍下东航客机坠落瞬间ld内部就是经过=进行截取,别离获取插件称号pluginName和类界说defineClass
    • 经过架构师工资结构返回插件界说的实例new PluginDefine(pluginName, defin接口测试eCla监控安装流程ss)
  • 返回插件界说调集List<P接口自动化luginDefine>
  • 遍历插件调集,运用反射的办法创立插件实例。
  • 返回一切现已加载的插件调集List&实例化和初始化的区别lt;AbstractClassEnhancePluginDefine>

得到一切的插件调集后,new类的实例化 PluginFinder(List<AbstractC接口卡la监控摄像头品牌排行ssEnhancePluginDefine>)的首要作用是为已加载的插件做缓存,而且供给快速查找已加载插件的能力。

2.1.2 创立AgentBuild实例化servlet类异常er

ByteBuddy:Byt接口类型e Buddy是一个字节码生成和操作库,用于在Java应用程序运转时创立和修正Java类,而无需编译器的协助。

2架构师和程序员的区别.1.2.1 实例化B接口是什么yteBuddy

    final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));

其间IS_OPEN_DEBUGGING_CLASS假如开接口crc错误计数启,skywalking会相对于agent根目录的方位创架构图模板立文件夹,记载这些被插桩的类。用来和skywalking开发者解决兼容性问题。

2.1.2.2 创立AgentBulider

用来界说ByteBuddy的一些行为。如下疏忽无关的类:

    AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy).ignore(
        nameStartsWith("net.bytebuddy.")
                .or(nameStartsWith("org.slf4j."))
                .or(nameStartsWith("org.groovy."))
                .or(nameContains("javassist"))
                .or(nameContains(".asm."))
                .or(nameContains(".reflectasm."))
                .or(nameStartsWith("sun.reflect"))
                .or(allSkyWalkingAgentExcludeToolkit())
                .or(ElementMatchers.isSynthetic()));

2.1.2.3 界说边缘类调集:EdgeClasses

    JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();

其实Edge架构工程师Classes就是一个List,其间监控安装流程会包含ByteBuddy的中心类。

    public class ByteBuddyCoreClasses {
        private static final String SHADE_PACKAGE = "org.apache.skywalking.apm.dependencies.";
        public static final String[] CLASSES = {
            SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.RuntimeType",
            SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.This",
            SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.AllArguments",
            SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.AllArguments$Assignment",
            SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.SuperCall",
            SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.Origin",
            SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.Morph",
            };
    }

经过这些报名,咱们发现其实它们是一些annotation(注解)接口卡

2.1.2实例化和初始化的区别.4 将EdgeClasses注入BoostrapClassLoader

    BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);

这个方位涉及到后边要解说的东接口英文西,暂时先不解说。

可是关于类加载器的内容要简略描绘一下,咱们了解类加载器的同学应该知道java的类加优先级调度算法载联系:

一文探究【skywalking】怎么经过agent完结发动流程

为什么要注入到Boo优先级队列strapClassLoader?

自界说的ClassLoader只能在最下层,而AgentClassLoader经过字节码修正的类,是不可以被BootStrapClassLoade架构师工资r直接运用的,所以需求注入进去。

2.1.2.5 打开读鸿沟

这行首要为了解决jdk9中模块体系的跨模块类拜访问题。与本文重点无关,略过监控安装

    JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses);

2.1.2.6 AgentBuilder属性设置

    agentBuilder
            // 指定ByteBuddy修正的契合条件的类
            .type(pluginFinder.buildMatch())
            // 指定字节码增强东西
            .transform(new Transformer(pluginFinder))
            //指定字节码增强形式,REDEFINITION掩盖修正内容,RETRANSFORMATION保存修正内容(修正称号),
            .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
            // 注册监听器-监听反常情况,输出日子
            .with(new RedefinitionListener())
            // 对transform和反常情况监听,输出日志
            .with(new Listener())
            // 将界说好的agent注册到instrumentation
            .installOn(instrumentation);

2.1.3 加载服务

ServiceManager.INSTANCE.boot();

如上所示ServiceManager架构师证书基于ServerLoader完结,是J优先级是什么意思DK供给的一种SPI机制。

boot()办法:

public void boot() {
    // 加载一切的服务到bootServices
    bootedServices = loadAllServices();
    // 预备
    prepare();
    // 发动
    startup();
    //完结
    onComplete();
}

2.1.3.1 bootedServices是什么?

    private Map<Class, BootService> bootedServices = Collections.emptyMap();

其间的BootService是一个接口,其包含了服务的生命周期,插件开端工作时,需求被发动,如下所示:

    public interface BootService {
        /**
         * 预备
         * @throws Throwable
         */
        void prepare() throws Throwable;
        /**
         * 发动
         * @throws Throwable
         */
        void boot() throws Throwable;
        /**
         * 完结
         * @throws Throwable
         */
        void onComplete() throws Throwable;
        /**
         * 停止
         * @throws Throwable
         */
        void shutdown() throws Throwable;
        /**
         * 优先级,优先级高的BootService会优先发动
         */
        default int priority() {
            return 0;
        }
    }

一切完结了BootService接口的服务都会在此被加载。

2.1.3.2 loadAllServices()

这个办法经过jdk供给的SPI机制,ServiceLoader将需求的类加载进来,而这些类被界说在指定的装备文件傍边:

一文探究【skywalking】怎么经过agent完结发动流程

装备文件内容如下:

    org.apache.skywalking.apm.agent.core.remote.TraceSegmentServiceClient
    org.apache.skywalking.apm.agent.core.context.ContextManager
    org.apache.skywalking.apm.agent.core.sampling.SamplingService
    org.apache.skywalking.apm.agent.core.remote.GRPCChannelManager
    org.apache.skywalking.apm.agent.core.jvm.JVMMetricsSender
    org.apache.skywalking.apm.agent.core.jvm.JVMService
    org.apache.skywalking.apm.agent.core.remote.ServiceManagementClient
    org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService
    org.apache.skywalking.apm.agent.core.commands.CommandService
    org.apache.skywalking.apm.agent.core.commands.CommandExecutorService
    org.apache.skywalking.apm.agent.core.profile.ProfileTaskChannelService
    org.apache.skywalking.apm.agent.core.profile.ProfileSnapshotSender
    org.apache.skywalking.apm.agent.core.profile.ProfileTaskExecutionService
    org.apache.skywalking.apm.agent.core.meter.MeterService
    org.apache.skywalking.apm.agent.core.meter.MeterSender
    org.apache.skywalking.apm.agent.core.context.status.StatusCheckService
    org.apache.skywalking.apm.agent.core.remote.LogReportServiceClient
    org.apache.skywalking.apm.agent.core.conf.dynamic.ConfigurationDiscoveryService
    org.apache.skywalking.apm.agent.core.remote.EventReportServiceClient
    org.apache.skywalking.apm.agent.core.ServiceInstanceGenerator

经过下面的办法将上面装备的一切完结了bootService的类加载到allServices傍架构是什么意思边。

    void load(List<BootService> allServices) {
        for (final BootService bootService : ServiceLoader.load(BootService.class, AgentClassLoader.getDefault())) {
            allServices.add(bootService);
        }
    }

在上一步加载完悉数的类之后,需求去遍历这些类,得到一个bootedServices的调集。在看代码逻辑之前,需求看下skywalking界说架构师和程序员的区别优先级排序两个注解:

  • @DefaultImplementor 默许完接口类型
  • @OverrideImplementor 掩盖完结

带有@DefaultImplementor注解的类,表示它会有类去承继它,承继它的类需求带有优先级 @Overrid架构图模板eImplementor注解,并指定承继的类的称号,例如:

默许完结类优先级c语言

    @DefaultImplementor
    public class JVMMetricsSender implements BootService, Runnable, GRPCChannelListener 
承继它的类:
    @OverrideImplementor(JVMMetricsSender.class)
    public class KafkaJVMMetricsSender extends JVMMetricsSender implements KafkaConnectionStatusListener 

在了解了skywalking的默许类和承继类实例化对象的机制后,有代码逻辑如下:

    private Map<Class, BootService> loadAllServices() {
        Map<Class, BootService> bootedServices = new LinkedHashMap<>();
        List<BootService> allServices = new LinkedList<>();
        // SPI加载
        load(allServices);
        // 遍历
        for (final BootService bootService : allServices) {
            Class<? extends BootService> bootServiceClass = bootService.getClass();
            // 是否带有默许完结
            boolean isDefaultImplementor = bootServiceClass.isAnnotationPresent(DefaultImplementor.class);
            if (isDefaultImplementor) {// 是默许完结
                // 是默许完结,没有增加到bootedServices
                if (!bootedServices.containsKey(bootServiceClass)) {
                    //参加bootedServices
                    bootedServices.put(bootServiceClass, bootService);
                } else {
                    //ignore the default service
                }
            } else {// 不是默许完结
                // 是否是掩盖完结
                OverrideImplementor overrideImplementor = bootServiceClass.getAnnotation(OverrideImplementor.class);
                // 不是掩盖
                if (overrideImplementor == null) {
                    // bootedServices没有
                    if (!bootedServices.containsKey(bootServiceClass)) {
                        //参加bootedServices
                        bootedServices.put(bootServiceClass, bootService);
                    } else {
                        throw new ServiceConflictException("Duplicate service define for :" + bootServiceClass);
                    }
                } else {
                    // 是掩盖,value获取的是其承继的类targetService
                    Class<? extends BootService> targetService = overrideImplementor.value();
                    // 假如bootedServices现已包含targetService
                    if (bootedServices.containsKey(targetService)) {
                        // 判断targetServices是否是默许完结
                        boolean presentDefault = bootedServices.get(targetService)
                                                               .getClass()
                                                               .isAnnotationPresent(DefaultImplementor.class);
                        // 是默许完结
                        if (presentDefault) {
                            // 增加进去
                            bootedServices.put(targetService, bootService);
                        } else {
                            // 没有默许完结,不能掩盖,抛出反常
                            throw new ServiceConflictException(
                                "Service " + bootServiceClass + " overrides conflict, " + "exist more than one service want to override :" + targetService);
                        }
                    } else {
                        // 是掩盖完结,它掩盖的默许完结还没有被加载进来
                        bootedServices.put(targetService, bootService);
                    }
                }
            }
        }
        return bootedServices;
    }

2.1.3.3 p监控拍下东航客机坠落瞬间repare(),startup(),onComplete()

在加载完悉数的类之后,还有预备,发动和完结等分操作,它们的代码完结相同,如下所示:

private void prepare() {
    // 获取一切的类
    bootedServices.values().stream()
            // 依据优先级排序,BootService的priority
            .sorted(Comparator.comparingInt(BootService::priority))
            // 遍历
            .forEach(service -> {
        try {
            // 履行每一个BootService的完结类的prepare()办法
            service.prepare();
        } catch (Throwable e) {
            LOGGER.error(e, "ServiceManager try to pre-start [{}] fail.", service.getClass().getName());
        }
    });
}
private void startup() {
    bootedServices.values().stream()
            // 依据优先级排序,BootService的priority
            .sorted(Comparator.comparingInt(BootService::priority))
            // 遍历
            .forEach(service -> {
        try {
            // 履行每一个BootService的完结类的boot()办法
            service.boot();
        } catch (Throwable e) {
            LOGGER.error(e, "ServiceManager try to start [{}] fail.", service.getClass().getName());
        }
    });
}
private void onComplete() {
    // 遍历
    for (BootService service : bootedServices.values()) {
        try {
            // 履行每一个BootService的完结类的onComplete()办法
            service.onComplete();
        } catch (Throwable e) {
            LOGGER.error(e, "Service [{}] AfterBoot process fails.", service.getClass().getName());
        }
    }
}

2.1.4 ShutdownHook

为skywalking的运转服务增加一个shutdo优先级表wn的钩子。

Runtime.getRuntime()
        .addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));

shutdown办法,与预备和发动办法不架构图模板同之处在于,shutdown的排序办法是依照优先级的倒序排序,为了高雅的停机,后发动的服务,先停机:

public void shutdown() {
    bootedServices.values().stream().
            // 排序,依照优先级的倒序
            sorted(Comparator.comparingInt(BootService::priority).reversed())
            .forEach(service -> {
        try {
            // 履行每个服务的shutdown
            service.shutdown();
        } catch (Throwable e) {
            LOGGER.error(e, "ServiceManager try to shutdown [{}] fail.", service.getClass().getName());
        }
    });
}

2.2 小结

本章节用了不小的篇幅解说premain办法的源码发动过程,首要包含以下的方面:

  • 装备加载
  • 插件加载
  • AgentBUilder创立
  • skywalki架构师工资ng服务的加载

本章首要在于解说发动流程,代码量较大,涉及到字节码增强的关键暂时未解说。

三、总结

到此为止,关于skywalking的相关发动优先级调度算法流程就基本介绍完结了架构师和程序员的区别。之所以说是基本完结,是由于内部还以些关于插件发动流程的部分没有详细解说,比如:

  • transform的工作流程
  • 三种插装办法的原理
    • 静态办法插桩
    • 结构器插桩
    • 实例办法插桩监控家用远程手机

限于篇幅原因,后续架构师证书文章继续解说。

经过本篇文章,信任您必定也有了监控可以保存多少天不少的收成:

  • 静态agent和动态agent的概念和运用办法
  • skywalking运用def文件界说架构图怎么画插件的办法,即插件的加载过程
  • skywalin优先级是什么意思g经过ByteBuddy完结字节码增强
  • 类加载器的相关知识
  • BootService的界说和运用架构是什么意思办法
  • JDK SPI办法完结类加载。
  • Skywalking所特有的默许完结,掩盖完结的注解界说办法。

除了以上详细的,还会看到诸如策略形式、制作者形式、观察者等规划形式。实例化是什么意思

阅览源码,虽然许多时分会让你感到不流畅难懂,可监控可以保存多少天是当你坚持下来,收成绝对是意想不到的。养成阅览源码的好习惯,将会在编码工作中起到很大的协助。

本文到此结束,感谢阅览!


我正在参加技能社区创作者签约计划招募活动,点击链接报名投稿。

发表评论

提供最优质的资源集合

立即查看 了解详情