APM - 使用JavaAgent+Javassit 插桩C3P0



APM - 使用JavaAgent+Javassit 插桩C3P0

核心思想
 <bean id="dataSource"  
        class="com.mchange.v2.c3p0.ComboPooledDataSource"  ......


很熟悉吧,我们要插桩的这个对象就是 ComboPooledDataSource ,

如何很直观的展示出来的

  1. 实时获取ComboPooledDataSource的属性信息
  2. 简洁直观的展示相关属性信息

实现第一个,那就在ComboPooledDataSource构造函数后下手,将ComboPooledDataSource放到System Properties 中, 然后开启一个HTTP服务,对外提供服务访问即可。


编码实现
package com.artisan.agent.collect.c3p0;import com.sun.net.httpserver.Headers;import com.sun.net.httpserver.HttpExchange;import com.sun.net.httpserver.HttpHandler;import com.sun.net.httpserver.HttpServer;import javassist.ClassPool;import javassist.CtClass;import javassist.LoaderClassPath;import java.io.IOException;import java.io.OutputStream;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;import java.net.InetSocketAddress;import java.security.ProtectionDomain;import java.util.concurrent.Executors;/**
 * @author 小工匠
 * @version 1.0
 * @description: C3P0插桩
 * @date 2020/8/29 9:15
 * @mark: show me the code , change the world
 */public class C3P0Agent {

    // 要插装的类
    static String targetClass = "com.mchange.v2.c3p0.ComboPooledDataSource";

    public static void premain(String args , Instrumentation instrumentation){
        // 类转换器处理插桩逻辑
        instrumentation.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader loader,
                                    String className,
                                    Class<?> classBeingRedefined,
                                    ProtectionDomain protectionDomain,
                                    byte[] classfileBuffer)   {
                //  插桩后的对象
                byte[] result = null;
                // 条件判断
                if (className != null && className.replace("/", ".").equals(targetClass)){
                    // 实例化pool , 将当前的ClassLoader设置到pool
                    ClassPool pool = new ClassPool();
                    pool.insertClassPath(new LoaderClassPath(loader));


                    try {
                        // 获取目标对象
                        CtClass ctl = pool.get(targetClass);
                        // 获取构造函数,插桩  将对象放入系统属性中
                        ctl.getConstructor("()V") //构造函数
                                .insertAfter("System.getProperties().put(\"c3p0Source$agent\", $0);"); // $0 this本身
                        // 转成class
                        result = ctl.toBytecode();
                        // 暴漏HTTP服务
                        new C3P0Agent().openHttpServer();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return result;
            }
        });

    }

    /**
     * 对外提供Http 服务展示DataSource当前状态
     * @throws IOException
     */
    private void openHttpServer() throws IOException {
        InetSocketAddress addr = new InetSocketAddress(7777);
        HttpServer server = HttpServer.create(addr, 0);
        // 设置上下文
        server.createContext("/", new MyHttpHandler());
        server.setExecutor(Executors.newCachedThreadPool());
        server.start();
    }


    private class MyHttpHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            Headers responseHeaders = exchange.getResponseHeaders();
            responseHeaders.set("Content-Type", "text/plain;charset=UTF-8");
            exchange.sendResponseHeaders(200, 0);
            OutputStream responseBody = exchange.getResponseBody();
            // 输出c3p0状态
            responseBody.write(C3P0Agent.this.getStatus().getBytes());
            responseBody.flush();
            responseBody.close();
        }
    }


    public String getStatus() {
        Object source2 = System.getProperties().get("c3p0Source$agent");
        if (source2 == null) {
            return "未初始任何c3p0数据源";
        }
        return source2.toString();
    }}



打包
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>artisan-apmartifactId>
        <groupId>org.examplegroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>apm-agentartifactId>
    <dependencies>
        <dependency>
            <groupId>org.javassistgroupId>
            <artifactId>javassistartifactId>
            <version>3.18.1-GAversion>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>


        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.1.0version>
            <scope>providedscope>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.32version>
            <scope>providedscope>
        dependency>
        <dependency>
            <groupId>c3p0groupId>
            <artifactId>c3p0artifactId>
            <version>0.9.1.2version>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-jar-pluginartifactId>
                <version>2.2version>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Project-name>${project.name}Project-name>
                            <Project-version>${project.version}Project-version>
                            <Boot-Class-Path>javassist-3.18.1-GA.jarBoot-Class-Path>
                            <Premain-Class>com.artisan.agent.collect.c3p0.C3P0AgentPremain-Class>
                            <Can-Redefine-Classes>trueCan-Redefine-Classes>
                            <Can-Retransform-Classes>trueCan-Retransform-Classes>
                        manifestEntries>
                    archive>
                    <skip>trueskip>
                configuration>
            plugin>

            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-shade-pluginartifactId>
                <executions>
                    <execution>
                        <phase>packagephase>
                        <goals>
                            <goal>shadegoal>
                        goals>
                        <configuration>
                            <artifactSet>
                                <includes>
                                    <include>org.javassist:javassistinclude>
                                includes>
                            artifactSet>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.artisan.agent.collect.c3p0.C3P0AgentmainClass>
                                transformer>
                            transformers>
                        configuration>
                    execution>
                executions>
            plugin>
        plugins>
    build>project>


打包的时候,连同javassist也打包进去

APM - 使用JavaAgent+Javassit 插桩C3P0
APM - 使用JavaAgent+Javassit 插桩C3P0
APM - 使用JavaAgent+Javassit 插桩C3P0


配置验证

在启动的JVM参数中配置如下信息

-javaagent:D:\IdeaProjects\artisan-apm\apm-agent\target\apm-agent-1.0-SNAPSHOT.jar


APM - 使用JavaAgent+Javassit 插桩C3P0

然后,访问 http:// localhost:7777

APM - 使用JavaAgent+Javassit 插桩C3P0


上一篇:javaagent入门


下一篇:JavaAgent简单学习