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檔案中進行了配置
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TSU9UNFR0YzB3MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3EjN5ATNxkTM5IjNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
進入該方法,其會解析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自動注入,注入
PluginContextLoadResult
,
PluginContextLoadResult
通過
PluginContextLoadResultProvider
提供,這裡又自動注入了
ProfilerPluginContextLoader
/**
* pinpoint 分析插件加載器,用于加載pinpoint的各種插件,注意隻是加載,并沒有轉換(transform)
* @author HyunGil Jeong
*/
public interface ProfilerPluginContextLoader {
/**
* 加載所有插件,因為pinpoint的分析插件都需要實作ProfilerPlugin接口
* */
PluginsSetupResult load(List<ProfilerPlugin> profilerPlugins);
}
而
ProfilerPluginContextLoader
擷取的時候依賴了
PluginSetup
@Inject
public 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
中進行加載,如下:
@Override
public 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
@Override
public 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方法
@Override
public 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 api
if (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進行加載