pinpoint 版本:2.0.3-SNAPSHOT
pinpoint利用java agent 特性,提供了一个agent jar包,此jar包会在应用运行之前先运行,agent和应用在同一个进程。pinpoint通过对各个第三方包编写特定的插件,这些插件在agent运行时被加载,通过ASM对第三方包的类进行修改(Intercetor),应用在运行时使用的第三方包的类即是pinpoint修改后的,从而实现全链路追踪的目的。

Agent加载流程

agent的入口在 com.navercorp.pinpoint.bootstrap.PinpointBootStrap的premain方法,其在pom文件中进行了配置

进入该方法,其会解析agent jar包所在的目录,然后创建启动类PinpointStarter并调用start方法,在start方法中,其创建com.navercorp.pinpoint.profiler.DefaultAgent,关键在于DefaultAgent的构造方法中的下面这行代码:

        //在构造函数的这一步里就对所有的插件进行了加载this.applicationContext = newApplicationContext(agentOption);

进入

    protected ApplicationContext newApplicationContext(AgentOption agentOption) {Assert.requireNonNull(agentOption, "agentOption");ProfilerConfig profilerConfig = Assert.requireNonNull(agentOption.getProfilerConfig(), "profilerConfig");ModuleFactoryResolver moduleFactoryResolver = new DefaultModuleFactoryResolver(profilerConfig.getInjectionModuleFactoryClazzName());ModuleFactory moduleFactory = moduleFactoryResolver.resolve();return new DefaultApplicationContext(agentOption, moduleFactory);}

上述代码中,ModuleFactory默认为ApplicationContextModuleFactory,这个是Guice依赖注入的module factory,pinpoint通过guice来实现类似spring的依赖自动注入,进入DefaultApplicationContext的构造方法

        //设置guice的依赖注入final Module applicationContextModule = moduleFactory.newModule(agentOption);this.injector = Guice.createInjector(Stage.PRODUCTION, applicationContextModule);

上面这两行代码完成了guice的模块依赖注入配置,在ApplicationContextModuleFactory中会进行各种依赖配置,如下

我们主要关注 ClassFileTransformer的实现,可以看到它的实现是

bind(ClassFileTransformer.class).toProvider(ClassFileTransformerProvider.class).in(Scopes.SINGLETON);

ClassFileTransformerProvider中通过guice自动注入,注入PluginContextLoadResultPluginContextLoadResult通过PluginContextLoadResultProvider提供,这里又自动注入了ProfilerPluginContextLoader

/*** pinpoint 分析插件加载器,用于加载pinpoint的各种插件,注意只是加载,并没有转换(transform)* @author HyunGil Jeong*/
public interface ProfilerPluginContextLoader {/*** 加载所有插件,因为pinpoint的分析插件都需要实现ProfilerPlugin接口* */PluginsSetupResult load(List<ProfilerPlugin> profilerPlugins);
}

ProfilerPluginContextLoader获取的时候依赖了PluginSetup

    @Injectpublic ProfilerPluginContextLoaderProvider(ProfilerConfig profilerConfig,@ConfiguredApplicationType ServiceType configuredApplicationType,PluginSetup pluginSetup,InstrumentEngine instrumentEngine, BootstrapCore bootstrapCore,@PluginJars List<PluginJar> pluginJars) {this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig");//配置文件配置的应用类别this.configuredApplicationType = Assert.requireNonNull(configuredApplicationType, "configuredApplicationType");this.pluginSetup = Assert.requireNonNull(pluginSetup, "pluginSetup");Assert.requireNonNull(instrumentEngine, "instrumentEngine");Assert.requireNonNull(bootstrapCore, "bootstrapCore");this.classInjectorFactory = new ClassInjectorFactory(instrumentEngine, bootstrapCore);this.pluginJars = Assert.requireNonNull(pluginJars, "pluginJars");}

真正引发查找并加载插件位于
DefaultPluginContextLoadResult的构造方法(自动注入的时候被调用),如下:

    public DefaultPluginContextLoadResult(ProfilerPluginContextLoader profilerPluginContextLoader, ClassLoader pluginClassLoader) {Assert.requireNonNull(profilerPluginContextLoader, "profilerPluginConfigurer");Assert.requireNonNull(pluginClassLoader, "pluginClassLoader");ProfilerPluginLoader profilerPluginLoader = new ProfilerPluginLoader();List<ProfilerPlugin> profilerPlugins = profilerPluginLoader.load(pluginClassLoader);//加载插件的地方this.pluginsSetupResult = profilerPluginContextLoader.load(profilerPlugins);}

ServiceType加载流程

ServiceType的加载位于ProfilerPluginContextLoaderProvider的构造方法自动注入@ConfiguredApplicationType最终在类TraceMetadataLoaderProvider中进行加载,如下:

    @Overridepublic TraceMetadataLoader get() {TraceMetadataProviderLoader traceMetadataProviderLoader = new TraceMetadataProviderLoader();//这时候的pluginClassLoader已经加载了各个插件URL了List<TraceMetadataProvider> traceMetadataProviders = traceMetadataProviderLoader.load(pluginClassLoader);TraceMetadataLoader traceMetadataLoader = new TraceMetadataLoader(commonLoggerFactory);traceMetadataLoader.load(traceMetadataProviders);return traceMetadataLoader;}

目前pinpoint对于ServiceType的加载有两种方式,一种是老的通过java spi的方式,一种是现在推荐的yml格式,在traceMetadataProviderLoader.load(pluginClassLoader);中会加载两种方式实现的ServiceType

    @Overridepublic List<TraceMetadataProvider> load(ClassLoader classLoader) {List<TraceMetadataProvider> traceMetadataProviders = new ArrayList<TraceMetadataProvider>();traceMetadataProviders.addAll(fromMetaFiles(classLoader));traceMetadataProviders.addAll(fromServiceLoader(classLoader));return traceMetadataProviders;}

ProfilerPlugin加载流程

在编写pinpoint的插件的时候,都会实现ProfilerPlugin接口,代码List<ProfilerPlugin> profilerPlugins = profilerPluginLoader.load(pluginClassLoader);通过java spi获取所有实现了此接口的类,然后在代码 profilerPluginContextLoader.load(profilerPlugins)中,最终在DefaultPluginSetup的setup方法

    @Overridepublic PluginSetupResult setupPlugin(ProfilerPluginGlobalContext globalContext, ProfilerPlugin profilerPlugin, ClassInjector classInjector) {final ProfilerConfig profilerConfig = globalContext.getConfig();final ClassFileTransformerLoader transformerRegistry = new ClassFileTransformerLoader(profilerConfig, dynamicTransformTrigger);final DefaultProfilerPluginSetupContext setupContext = new DefaultProfilerPluginSetupContext(globalContext);final GuardProfilerPluginSetupContext guardSetupContext = new GuardProfilerPluginSetupContext(setupContext);final InstrumentContext instrumentContext = new PluginInstrumentContext(profilerConfig, instrumentEngine, dynamicTransformTrigger, classInjector, transformerRegistry);final GuardInstrumentContext guardInstrumentContext = preparePlugin(profilerPlugin, instrumentContext);try {// WARN external plugin apiif (logger.isInfoEnabled()) {logger.info("{} Plugin setup", profilerPlugin.getClass().getName());}profilerPlugin.setup(guardSetupContext);} finally {guardSetupContext.close();guardInstrumentContext.close();}PluginSetupResult setupResult = new PluginSetupResult(setupContext, transformerRegistry);return setupResult;}

调用我们插件类的setup方法,一般我们还会实现 TransformTemplateAware,这是在这个类的preparePlugin方法进行设置

这样便执行到了各个插件的setup方法,通过asm将各种transform进行加载

Pinpoint Agent加载流程分析相关推荐

  1. Android6.0 keyguard锁屏加载流程分析

    锁屏界面的加载通常在android中有两种方式触发:android系统开机和screenOff(灭屏)后,再screenOn; 先来看 android系统开机时候的锁屏加载流程: 首先在系统启动过程中 ...

  2. Launcher3 桌面加载流程分析

    Launcher3 桌面加载流程分析 主入口Launcher 首先来看Launcher.java的onCreate方法,里面代码很多,只看主流程部分: @Override protected void ...

  3. linux驱动加载流程分析

    linux驱动加载流程分析 内核是如何加载驱动的,有些是编译到内核里面,有些事编译成ko,让系统自动加载.总的说来,在Linux下可以通过两种方式加载驱动程序:静态加载和动态加载. 静态加载就是把驱动 ...

  4. MultiDex加载流程分析

    MultiDex加载流程分析 只介绍主要流程,multiDex源码已经上传到https://github.com/AlexSmille/google-android-support-source-an ...

  5. Spring初始化加载流程分析

    关于Spring框架的介绍,网上有很多非常好的详细的文章,如果在本篇博客中没有了解到自己想要的东西,个人能力有限,只能使用博客记录一下自己目前了解的知识点了! 本篇博客将大致介绍一下Spring框架的 ...

  6. Android 4.0 ICS SystemUI浅析——StatusBar加载流程分析

    前面两篇文章< Android 4.0 ICS SystemUI浅析--SystemUI启动流程>.< Android 4.0 ICS SystemUI浅析--StatusBar结构 ...

  7. NioEventLoop加载流程分析

    一.我们首先看NioEventLoopGroup创建和初始化过程. EventLoopGroup workEventLoopGroup = new NioEventLoopGroup(new Name ...

  8. 【CEGUI】资源加载流程

    CEGUI资源加载流程 CEGUI版本 0.8.7 主要资源类型 Scheme scheme资源(包括图像集.字体资源.窗口外观信息.类型映射)等.可以通过".scheme"&qu ...

  9. Tomcat:应用加载原理分析

    前情回顾 上一篇文章主要了解了一下Tomcat启动入口,以及初步的分析了Tomcat的启动流程,下面我们将会解密Tomcat应用部署的实际流程. 一.直观对比 虽然前面已经说了那么多关于Tomcat的 ...

最新文章

  1. linux 查看线程详细信息,Linux 下查看线程信息
  2. 分析型数据库受大数据市场追捧
  3. sql server 交叉表查询实例-成绩统计
  4. 冒泡排序html代码,冒泡排序.html
  5. DCMTK:将标准图像格式转换为DICOM的实用程序
  6. 根据map键值对,生成update与select语句,单条执行语句
  7. android 广播 7.0变化,安卓7.0到底带来了那些变化?
  8. 终极Java日志字典:开发人员最常记录的单词是什么?
  9. webview代码实例化_WebView常用类和基本方法详解
  10. 三大院士、十大数据库掌门人,岳麓对话开启数字经济新时代!
  11. 2021年B站创作者生态报告
  12. Get AD Object and disable move delete AD account script 查询删除AD账户计算机
  13. 实现全排列的另一种方法(续)
  14. mysql5.7审计功能开启_开启mysql的审计功能
  15. python做路径图_python实现生成图片路径和对应标签
  16. sketchup 计算机配置,草图大师2020对电脑配置要求
  17. 自然语言处理(3)——形式语言与自动机
  18. 精品餐饮业奢华西餐专业PPT-朴尔PPT
  19. 面对传销,该怎么处理
  20. 下载python开发环境

热门文章

  1. Windows系统盘盘符修改
  2. 逆向获取博客园APP代码
  3. Linux网络——网桥设置管理
  4. 黑马程序员——C基础之迷宫游戏
  5. http://www.cnblogs.com/hoojo/archive/2011/06/08/2075201.html
  6. 聚财云库:告诉你2021年,你该有的副业思维
  7. 京东智能店长主图长图功能怎么用?
  8. 加布里埃拉·梅利内斯库《复原》
  9. promise对象里resolve和reject状态讲解及Promise.all()的使用
  10. 【洛谷4815】[CCO2014] 狼人游戏(树形DP)