Understanding the javaagent components 理解探针组件

The javaagent jar can logically be divided into 3 parts:

探针在逻辑上分为三部分

  • Modules that live in the system class loader 被系统类(应用)加载器加载的组件
  • Modules that live in the bootstrap class loader 被启动类加载器加载的组件
  • Modules that live in the agent class loader 被探针类加载器加载的组件

Modules that live in the system class loader

javaagent module

This module consists of single classio.opentelemetry.javaagent.OpenTelemetryAgent which implements Java instrumentation agent.
This class is loaded during application startup by application classloader.
Its sole responsibility is to push agent’s classes into JVM’s bootstrap classloader and immediately delegate to
io.opentelemetry.javaagent.bootstrap.AgentInitializer (now in the bootstrap class loader) class from there.

这个模块由单一的 classio.opentelemetry.javaagent.OpenTelemetryAgent 组成,以实现 Java Agent。 这个类在应用程序启动时由应用类加载器加载。 它的唯一职责是将Agent的类推入JVM的引导类加载器,并立即委托给 io.opentelemetry.javaagent.bootstrap.AgentInitializer(现在在启动类加载器中)类。

Modules that live in the bootstrap class loader

javaagent-bootstrap module

io.opentelemetry.javaagent.bootstrap.AgentInitializer and a few other classes that live in the bootstrap class loader but are not used directly by auto-instrumentation

io.opentelemetry.javaagent.bootstrap.AgentInitializer和其他一些存在于bootstrap类加载器中但不直接用于auto-instrumentation

instrumentation-api and javaagent-api modules

These modules contain support classes for actual instrumentations to be loaded
later and separately. These classes should be available from all possible
classloaders in the running application. For this reason the javaagent module puts
all these classes into JVM’s bootstrap classloader. For the same reason this
module should be as small as possible and have as few dependencies as
possible. Otherwise, there is a risk of accidentally exposing this classes to
the actual application.

这些模块包含了实际instrumentations的支持类,将在以后单独加载。这些类应该可以从运行中的应用程序的所有可能的类加载器中获得。出于这个原因,javaagent 模块将所有这些类放入 JVM 的启动类加载器。出于同样的原因,这个模块应该尽可能的小,并且有尽可能少的依赖性。否则,就有可能不小心把这些类暴露在实际应用中。

instrumentation-api contains classes that are needed for both library and auto-instrumentation,
while javaagent-api contains classes that are only needed for auto-instrumentation.

Modules that live in the agent class loader

javaagent-tooling, javaagent-extension-api modules and instrumentation submodules

Contains everything necessary to make instrumentation machinery work,
including integration with ByteBuddy and actual
library-specific instrumentations. As these classes depend on many classes
from different libraries, it is paramount to hide all these classes from the
host application. This is achieved in the following way:

包含使 instrumentation 设备工作的一切必要条件,包括与ByteBuddy的集成和实际的库专用仪器。由于这些类依赖于不同库中的许多类,所以最重要的是将所有这些类从主机应用程序中隐藏起来。这可以通过以下方式实现。

  • When javaagent module builds the final agent, it moves all classes from
    instrumentation submodules, javaagent-tooling and javaagent-extension-api modules
    into a separate folder inside final jar file, calledinst.
    In addition, the extension of all class files is changed from class to classdata.
    This ensures that general classloaders cannot find nor load these classes.

    当 javaagent 模块构建最终代理时,它将所有来自 instrumentation 子模块、javaagent-tooling 和 javaagent-extension-api 模块的类转移到最终 jar 文件中的一个单独文件夹,称为inst。此外,所有类文件的扩展名也从class改为classdata。这样可以保证一般的类加载器找不到也加载不了这些类。

  • When io.opentelemetry.javaagent.bootstrap.AgentInitializer is invoked, it creates an
    instance of io.opentelemetry.javaagent.bootstrap.AgentClassLoader, loads an
    io.opentelemetry.javaagent.tooling.AgentInstaller from that AgentClassLoader
    and then passes control on to the AgentInstaller (now in the
    AgentClassLoader). The AgentInstaller then installs all of the
    instrumentations with the help of ByteBuddy. Instead of using agent classloader all agent classes
    could be shaded and used from the bootstrap classloader. However, this opens de-serialization
    security vulnerability and in addition to that the shaded classes are harder to debug.

    当调用io.opentelemetry.javaagent.bootstrap.AgentInitializer时,它会创建一个io.opentelemetry.javaagent.bootstrap.AgentClassLoader的实例,从该AgentClassLoader加载一个io.opentelemetry.javaagent.tooling.AgentInstaller,然后把控制权交给AgentInstaller(现在在AgentClassLoader中)。然后AgentInstaller在ByteBuddy的帮助下安装所有的仪器。而不是使用Agent类加载器,所有的代理类都可以从启动类加载器中着色和使用。然而,这打开了去序列化的安全漏洞,除此之外,阴影类更难调试。

The complicated process above ensures that the majority of
auto-instrumentation agent’s classes are totally isolated from application
classes, and an instrumented class from arbitrary classloader in JVM can
still access helper classes from bootstrap classloader.

上述复杂的过程保证了大部分自动探测代理的类与应用程序的类完全隔离,来自JVM中任意类加载器的探测类仍然可以访问来自启动类加载器的帮助类。

Agent jar structure

If you now look inside
javaagent/build/libs/opentelemetry-javaagent-<version>-all.jar, you will see the
following “clusters” of classes:

Available in the system class loader:

  • io/opentelemetry/javaagent/bootstrap/AgentBootstrap - the one class from javaagent
    module

Available in the bootstrap class loader:

  • io/opentelemetry/javaagent/bootstrap/ - contains the javaagent-bootstrap module
  • io/opentelemetry/javaagent/instrumentation/api/ - contains the javaagent-api module
  • io/opentelemetry/javaagent/shaded/instrumentation/api/ - contains the instrumentation-api module,
    shaded during creation of javaagent jar file by Shadow Gradle plugin
  • io/opentelemetry/javaagent/shaded/io/ - contains the OpenTelemetry API and its dependency gRPC
    Context, both shaded during creation of javaagent jar file by Shadow Gradle plugin
  • io/opentelemetry/javaagent/slf4j/ - contains SLF4J and its simple logger implementation, shaded
    during creation of javaagent jar file by Shadow Gradle plugin

Available in the agent class loader:

  • inst/ - contains javaagent-tooling and javaagent-extension-api modules and
    instrumentation submodules, loaded and isolated inside AgentClassLoader.
    Including OpenTelemetry SDK (and the built-in exporters when using the -all artifact).

initialization-sequence.svg
Image source
classloader-state.svg
Image source