Sermant运行流程学习条记,速来抄作业

打印 上一主题 下一主题

主题 541|帖子 541|积分 1625

本文分享自华为云社区《Sermant 的整体流程学习梳理》,作者:用友汽车信息科技(上海)有限公司 刘亚洲 Java研发工程师。
一、sermant架构

Sermant整体架构包括Sermant Agent、Sermant Backend、Sermant Injector、动态设置中央等组件。其中Sermant Agent是提供字节码增强基础本事及各类服务治理本事的核心组件,Sermant Backend、Sermant Injector、动态设置中央为Sermant提供其他本事的配套组件。

二、java agent和bytebuddy组合利用场景

比较典范的就是skywalking、sermant、arthas、mockito。如果说java agent开了一扇门,那么bytebuddy在开的这扇门中打开了一片新的天地。
三、Sermant的入口

前面我们说AgentLauncher是java agent的入口,为什么这么说呢?
  1. <manifestEntries>
  2.     <Premain-Class>com.huaweicloud.sermant.premain.AgentLauncher</Premain-Class>
  3.     <Agent-Class>com.huaweicloud.sermant.premain.AgentLauncher</Agent-Class>
  4.     <Can-Redefine-Classes>true</Can-Redefine-Classes>
  5.     <Can-Retransform-Classes>true</Can-Retransform-Classes>
  6. </manifestEntries>
复制代码
答案可以从pom.xml中找到答案,这里可以看到基于Premain-Class和Agent-Class的两个类都指向了AgentLauncher这个类。因此我们可以非常确认的肯定它就是javaagent入口类。类似于java程序有一个main的实行入口,而java agent有一个自己的入口类premain。
因此可以看到它的入口实行main:
  1.     /**
  2.      * premain
  3.      *
  4.      * @param agentArgs premain启动时携带的参数
  5.      * @param instrumentation 本次启动使用的instrumentation
  6.      */
  7.     public static void premain(String agentArgs, Instrumentation instrumentation) {
  8.         launchAgent(agentArgs, instrumentation, false);
  9.     }
  10.     /**
  11.      * agentmain
  12.      *
  13.      * @param agentArgs agentmain启动时携带的参数
  14.      * @param instrumentation 本次启动使用的instrumentation
  15.      */
  16.     public static void agentmain(String agentArgs, Instrumentation instrumentation) {
  17.         launchAgent(agentArgs, instrumentation, true);
  18.     }
复制代码
基于premain模式的和基于agent模式,区别在于是否为isDynamic。从这里我们可以看到这里提出了两个类值得我们去关注:AgentCoreEntrance、CommandProcessor,也即sermant这个项目标两个重点类。
更多需要了解的,可以参考byte-buddy这个开源项目。
四、入口方法实行的全流程


五、spi的加载过程

启动核心服务的过程是spi的加载过程,此时会初始化所有的服务。也即我们看到的所有服务会在此时会做一个启动的操作,同时还会启动变乱:
  1. service.start();
  2. collectServiceStartEvent(startServiceArray.toString());
复制代码
其实这个两个方法也做了很多事情。
启动服务做的事情:

collectServiceStartEvent则调用netty客户端向netty服务端发送数据。到服务端后,服务端举行数据处理,其网络的信息提供给backend模块方便后台展示查看。
六、以标签路由为例PluginService中扩展插件初始化

除此之外,还有一批实现了BaseService接口的,也即PluginService扩展插件服务基类,以标签路由为例,可以看你的其初始化的整个过程。

七、install的过程

同时我们可以看到install对应的process方法也是实行它的方法:
  1.   public ResettableClassFileTransformer install(Instrumentation instrumentation) {
  2.         AgentBuilder builder = new Default().disableClassFormatChanges();
  3.         // 遍历actions
  4.         for (BuilderAction action : actions) {
  5.             builder = action.process(builder);
  6.         }
  7.         // 执行安装操作,此时交给bytebuddy
  8.         return builder.installOn(instrumentation);
  9.     }
复制代码
从入参中的Instrumentation,我们往回看:ByteEnhanceManager.init(instrumentation)
这个方法内里定义了action的次序。
  1. public static void init(Instrumentation instrumentation) {
  2.         instrumentationCache = instrumentation;
  3.         builder = BufferedAgentBuilder.build();
  4.         // 初始化完成后,新增Action用于添加框架直接引入的字节码增强
  5.         enhanceForFramework();
  6.     }
复制代码
实行下面的过程:

我们根据上面的添加次序,来看初始化插件的次序:
  1. public static void enhanceDynamicPlugin(Plugin plugin) {
  2.         if (!plugin.isDynamic()) {
  3.             return;
  4.         }
  5.         // 获取描述信息
  6.         List<PluginDescription> plugins = PluginCollector.getDescriptions(plugin);
  7.         // 添加插件,然后执行安装操作
  8.         ResettableClassFileTransformer resettableClassFileTransformer = BufferedAgentBuilder.build()
  9.                 .addPlugins(plugins).install(instrumentationCache);
  10.         plugin.setClassFileTransformer(resettableClassFileTransformer);
  11.     }
复制代码
从引用上看,PluginSystemEntrance.initialize(isDynamic)中引用了这个方法。

可以看到这里的添加插件,可以理解为自定义的插件。
从sermant官网,我们可以知道:定义自定义插件,需要实现PluginDeclarer这个接口。也即从这里可以看到也即自定义的插件:
[code] /**     * 从插件网络器中获取所有插件声明器     *     * @param classLoader 类加载器     * @return 插件声明器集     */    private static List

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南七星之家

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表