Of Pinpoint (b) the principle of byte code enhancements

Technical pinpoint increase bytecode (some called dynamic probe technology) to implement non-invasive collection call chain. Its core to achieve the original or JVM-based javaagent mechanism to achieve. pinpoint specified at startup load path through the pinpoint Agent command, agent will do to intercept and modify application before loading the bytecode class files at startup, before and after the class method calls plus the link acquisition logic, in order to achieve chain Road acquisition.

-javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar

JavaAgent underlying mechanism is mainly dependent JVMTI, JVMTI full name JVM Tool Interface, some set of interfaces for users to expand the JVM exposed. JVMTI is based on event-driven, JVM each execution to a certain logic calls the callback interface of some event (if any), these interfaces can be used by developers to extend their own logic. But JVMTI interfaces are some of the collection, the need to implement the interface, which uses instrument java, you can understand the instrument is a JVMTI implementation to provide plug-in support for the JVM.

When the instrument is loaded at startup operation and loading support two modes, respectively, to achieve the Agent_OnLoad JVMTI Agent_OnAttach and methods; pinpoint currently used to load at startup mode, the following point of view is how to achieve pinpoint application to modify bytecodes at startup:

1. Pinpoint Agent class must be labeled jar package, and then inside the META-INF / MAINIFEST.MF must contain this attribute Premain-Class

Manifest-Version: 1.0
Premain-Class: com.navercorp.pinpoint.bootstrap.PinpointBootStrap
Archiver-Version: Plexus Archiver
Built-By: user
Can-Redefine-Classes: true
Pinpoint-Version: 1.6.0-SNAPSHOT
Can-Retransform-Classes: true
Created-By: Apache Maven 3.5.2
Build-Jdk: 1.8.0_152

Start classes implement the provisions of the instrument premain method (PinpointBootStrap.java), application priority calls this method before starting.

    public static void premain(String agentArgs, Instrumentation instrumentation) {
        if (agentArgs == null) {
            agentArgs = "";
        }
        logger.info(ProductInfo.NAME + " agentArgs:" + agentArgs);
 
        final boolean success = STATE.start();
        if (!success) {
            logger.warn("pinpoint-bootstrap already started. skipping agent loading.");
            return;
        }
        Map<String, String> agentArgsMap = argsToMap(agentArgs);
 
        final ClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver();
        if (!classPathResolver.verify()) {
            logger.warn("Agent Directory Verify fail. skipping agent loading.");
            logPinpointAgentLoadFail();
            return;
        }
 
        BootstrapJarFile bootstrapJarFile = classPathResolver.getBootstrapJarFile();
        appendToBootstrapClassLoader(instrumentation, bootstrapJarFile);
 
 
        PinpointStarter bootStrap = new PinpointStarter(agentArgsMap, bootstrapJarFile, classPathResolver, instrumentation);
        if (!bootStrap.start()) {
            logPinpointAgentLoadFail();
        }
 
    }

agentArgs program parameters premain function is obtained, along with "-javaagent" passed together. The difference is that the main function, this parameter is a string and not a string array, if there are a plurality of program parameters, the program itself will parse this string; agentArgs pinpoint the pinpoint is a jar.

Examples of a java.lang.instrument.Instrumentation instrumentation is automatically passed from the JVM. java.lang.instrument.Instrumentation instrument is an interface defined in the package, but also the core portion of the packet, almost all of which focus on the features methods, such as class definition and conversion operations and the like.

3. Tracking code is mainly premain call PinpointStarter.start () method

    boolean start() {
        /**省略代码*/
 
        try {
            // Is it right to load the configuration in the bootstrap?
            ProfilerConfig profilerConfig = DefaultProfilerConfig.load(configPath);
 
            // this is the library list that must be loaded
            List<URL> libUrlList = resolveLib(classPathResolver);
            AgentClassLoader agentClassLoader = new AgentClassLoader(libUrlList.toArray(new URL[libUrlList.size()]));
            final String bootClass = getBootClass();
            agentClassLoader.setBootClass(bootClass);
            logger.info("pinpoint agent [" + bootClass + "] starting...");
 
            AgentOption option = createAgentOption(agentId, applicationName, profilerConfig, instrumentation, pluginJars, bootstrapJarFile, serviceTypeRegistryService, annotationKeyRegistryService);
            Agent pinpointAgent = agentClassLoader.boot(option);
            pinpointAgent.start();
            registerShutdownHook(pinpointAgent);
            logger.info("pinpoint agent started normally.");
        } catch (Exception e) {
            // unexpected exception that did not be checked above
            logger.warn(ProductInfo.NAME + " start failed.", e);
            return false;
        }
        return true;
    }

4. Continue Tag main call pinpointAgent.start () method, while pinpointAgent herein is the realization DefaultAgent.

   public DefaultAgent(AgentOption agentOption, final InterceptorRegistryBinder interceptorRegistryBinder) {
 
        /**省略代码*/
 
        this.profilerConfig = agentOption.getProfilerConfig();
        this.instrumentation = agentOption.getInstrumentation();
        this.agentOption = agentOption;
 
        //默认使用ASM字节码引擎
        this.classPool = createInstrumentEngine(agentOption, interceptorRegistryBinder);
 
        if (logger.isInfoEnabled()) {
            logger.info("DefaultAgent classLoader:{}", this.getClass().getClassLoader());
        }
 
        //加载转换class字节码逻辑的插件,主要逻辑是将各个插件需要转换的目标class拦截器(拦截器是pinpoint自身封装的一类方法)存入List<ClassFileTransformer>中
        pluginContexts = loadPlugins(agentOption);
        //将List<ClassFileTransformer>转成HashMap<className,ClassFileTransformer>
        this.classFileTransformer = new ClassFileTransformerDispatcher(this, pluginContexts);
        this.dynamicTransformService = new DynamicTransformService(instrumentation, classFileTransformer);
 
        ClassFileTransformer wrappedTransformer = wrapClassFileTransformer(classFileTransformer);
        //调用jvm instrumentation工具方法
        instrumentation.addTransformer(wrappedTransformer, true);
 
 
        /**省略代码*/
    }

As can be seen, the method does not specify addTransformer which class to be converted, then the actual bytecode conversion did not occur. Conversion occurs after premain function executes, before the main function is executed, each time a class loading, Transform method will be executed once, to see whether the required conversion, then eventually by dynamicTransformService wrappedTransformer package HashMap <className, classFileTransformer> to determine currently loaded application classes need to convert.

5. Finally, we show the byte code conversion process by a pinpoint FIG:

  1. 1. JVM initializes and loads the System ClassLoader Pinpoint Agent by class; Instrumentation Create instance and calls the interface method Premain Pinpoint Agent and automatically passing Instrumentation instance;

  2. Pinpoint Agent loading plugins widget, registered class to which the transformer Instrumentation instance;

  3. System ClassLoader to load other applications Java classes, transformer method at this time of the call to register for classes to load java byte code conversion;

  4. The JVM class converted into the method area.

 

发布了8 篇原创文章 · 获赞 0 · 访问量 7268

Guess you like

Origin blog.csdn.net/fedorafrog/article/details/104170226