<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" ......
很熟悉吧,我们要插桩的这个对象就是 ComboPooledDataSource ,
如何很直观的展示出来的
- 实时获取ComboPooledDataSource的属性信息
- 简洁直观的展示相关属性信息
实现第一个,那就在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也打包进去
配置验证
在启动的JVM参数中配置如下信息
-javaagent:D:\IdeaProjects\artisan-apm\apm-agent\target\apm-agent-1.0-SNAPSHOT.jar
然后,访问 http:// localhost:7777