APM - 使用JavaAgent+Javassit 插桩C3P0

本文涉及的产品
云拨测,每月3000次拨测额度
简介: APM - 使用JavaAgent+Javassit 插桩C3P0

202010081834167.png

核心思想

<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();
    }
}


打包

<?xml version="1.0" encoding="UTF-8"?>
<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-apm</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>apm-agent</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.18.1-GA</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Project-name>${project.name}</Project-name>
                            <Project-version>${project.version}</Project-version>
                            <Boot-Class-Path>javassist-3.18.1-GA.jar</Boot-Class-Path>
                            <Premain-Class>com.artisan.agent.collect.c3p0.C3P0Agent</Premain-Class>
                            <Can-Redefine-Classes>true</Can-Redefine-Classes>
                            <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        </manifestEntries>
                    </archive>
                    <skip>true</skip>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <artifactSet>
                                <includes>
                                    <include>org.javassist:javassist</include>
                                </includes>
                            </artifactSet>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.artisan.agent.collect.c3p0.C3P0Agent</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>


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


20200929211304815.png


20200929211404195.png


20200929231342235.png


配置验证

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

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


20200929231254764.png

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


20200929231359934.png

相关文章
|
1月前
|
数据采集 Cloud Native Java
在 GraalVM 静态编译下无侵入实现可观测探索
在 GraalVM 静态编译下无侵入实现可观测探索
112412 10
|
Arthas Cloud Native Java
是谁在调用我?使用 arthas+jprofiler 做复杂链路分析
Arthas 是阿里巴巴开源的应用诊断利器,提供了 profiler 命令,可以生成热点火焰图。通过采样录制调用链路来做性能分析,极大提升了线上排查性能问题的效率。
是谁在调用我?使用 arthas+jprofiler 做复杂链路分析
|
4月前
|
监控 数据可视化 Java
VisualVM【实践 02】远程JVM监控的JMX配置及No supported for this JVM问题处理(Jstatd报错踩坑不计其数)
VisualVM【实践 02】远程JVM监控的JMX配置及No supported for this JVM问题处理(Jstatd报错踩坑不计其数)
118 0
|
8月前
|
Arthas 监控 Java
Arthas-java应用排障利器
Arthas-java应用排障利器
123 0
|
10月前
|
Java 数据库
skywalking05 - skywalking探针插件开发
skywalking05 - skywalking探针插件开发
167 0
|
11月前
|
监控 Java 应用服务中间件
APM - Hello Javaagent
APM - Hello Javaagent
76 0
|
11月前
|
监控 Java API
APM - Javassist 入门 生成一个简单类
APM - Javassist 入门 生成一个简单类
72 0
|
存储 安全 Java
深度探索JFR - JFR定位线上问题实例 - JFR导致的雪崩问题定位与解决
深度探索JFR - JFR定位线上问题实例 - JFR导致的雪崩问题定位与解决
深度探索JFR - JFR定位线上问题实例 - JFR导致的雪崩问题定位与解决
|
Arthas Kubernetes 监控
干货分享!JAVA诊断工具Arthas在Rainbond上实践~
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
|
存储 Prometheus 监控
APM 工具 SkyWalking 是什么
官方给 SkyWalking 的定义是一个分布式系统的应用程序性能监视工具,也是一个开源的可观测平台, 用于从服务和云原生基础设施收集、 分析、 聚合及可视化数据。
530 0