1.序言片面!一月三舟,托尔斯泰说:“多么伟大的作家,但他只是在写他自己的一面。”更何况是我,更何况是我们!我们虽然不写文章,但是写需求,写代码,写评论。当我们遇到需要讨论的问题时,它们往往会成为争论的焦点。这个好那个坏,随便你用!当你把路变窄的时候,你能得到的新思想、新想法、新视野,以及非常重要的收入也会减少。只有横向比较、借鉴、查漏补缺,才能让你的头脑有更多的想法,无论是写代码、理财,还是生活。2.需求目的你是使用IntelliJIDEA开发过程,需要获取执行SQL语句,复制出来验证时,总是这样的语句:SELECT*FROMUSERWHEREid=?和名字=?换个怎么样?输入参数的编号?当然这个需求其实并不大,甚至可以用其他的方法来解决。然后本章将为您提供一个新的想法,可能会以您几乎从未体验过的方式处理。所以在本章的案例中,我们使用基于IDEAPlugin的开发能力,将基于Javaagent能力的字节码插桩探针注入到代码中。然后通过增强的字节码,得到com.mysql.jdbc.PreparedStatement->executeInternal执行对象,从而得到可以直接测试的SQL语句。三、案例开发1.项目结构guide-idea-plugin-probe├──.gradle├──probe-agent│├──src││└──main││└──java││└──cn.bugstack.guide.idea.plugin││├──MonitorMethod.java││└──PreAgent.java│└──build.gradle└──probe-plugin│└──src││└──main││├──java│││└──cn.bugstack.guide.idea.plugin│││└──实用程序││││└──PluginUtil.java│││└──PerRun.java││└──资源││└──META-INF││└──plugin.xml│└──build.gradle├──build.gradle└──gradle.properties公众号:bugstackwormholestack回复:idea下载所有IDEA插件-in开发源码在这个IDEA插件项目中,项目结构分为两部分:probe-agent:probe模块,用于编译打包提供字节码增强服务,probe-plugin模块使用probe-plugin:插件模块,通过java.programPatcher加载字节码增强包,获取并打印执行数据库操作的SQL语句。2.字节码增强在SQL这里获取字节码增强的方法,使用Byte-Buddy字节码框架,它的使用方法更简单,在使用的过程中,有点像使用AOP拦截的方法来获取你需要的信息。另外,在gradle打包构建的时候,需要添加shadowJar模块来打包Premain-Class。这部分代码可以查看2.1Probe入口cn.bugstack.guide.idea.plugin.PreAgent//JVM首先尝试在agent类上调用如下方法publicstaticvoidpremain(StringagentArgs,Instrumentationinst){AgentBuilder.Transformertransformer=(builder,typeDescription,classLoader,javaModule)->{returnbuilder.method(ElementMatchers.named("executeInternal"))//拦截任何方法。拦截(MethodDelegation.to(MonitorMethod.class));//代表};newAgentBuilder.Default().type(ElementMatchers.nameStartsWith("com.mysql.jdbc.PreparedStatement")).transform(transformer).installOn(inst);}通过Byte-buddy配置,拦截匹配的类和方法,因为这个在类和方法下,可以获得完整的执行SQL语句。2.2拦截SQLcn.bugstack.guide.idea.plugin.MonitorMethod@RuntimeTypepublicstaticObjectintercept(@ThisObjectobj,@OriginMethodmethod,@SuperCallCallable>callable,@AllArgumentsObject...args)throwsException{try{返回callable.call();}finally{StringoriginalSql=(String)BeanUtil.getFieldValue(obj,"originalSql");StringreplaceSql=ReflectUtil.invoke(obj,"asSql");System.out.println("数据库名称:Mysql");System.out.println("线程ID:"+Thread.currentThread().getId());System.out.println("时间:"+newDate());System.out.println("原始SQL:\r\n"+originalSql);System.out.println("替换SQL:\r\n"+replaceSql);}}拦截方法入口是可配置的操作,比如@ThisObjectobj是获取当前类的执行对象,@OriginMethodmethod是获取执行方法。在finally块中,我们可以通过反射获取当前类的属性信息,通过反射获取执行的SQL,并打印出来。2.3编译打包在测试开发IDEAPlugin插件之前,我们需要进行一次打包操作。这个打包就是把字节码增强的代码打包成一个Jar包。在build.gradle->shadowJar中打包编译后,在build->libs下可以看到Jar:probe-agent-1.0-SNAPSHOT-all.jar该Jar用于字节码增强处理。2.4测试验证将编写好的字节码增强组件使用到插件之前,可以先做一次测试验证,避免每次都需要启动插件进行测试。单元测试publicclassApiTest{publicstaticvoidmain(String[]args)throwsException{StringURL="jdbc:mysql://127.0.0.1:3306/itstack?characterEncoding=utf-8";字符串USER="root";字符串密码="123456";Class.forName("com.mysql.jdbc.Driver");连接conn=DriverManager.getConnection(URL,USER,PASSWORD);Stringsql="SELECT*FROMUSERWHEREid=?ANDname=?";PreparedStatement语句=conn.prepareStatement(sql);statement.setLong(1,1L);statement.setString(2,"谢飞机");结果集rs=statement.executeQuery();while(rs.next()){System.out.println(rs.getString("name")+""+rs.getString("address"));}}}VMoptions:-javaagent:yourpath\libs\probe-agent-1.0-SNAPSHOT-all.jar注意,在测试运行时,需要为ApiTest配置VM选项,以便打印截获的SQL信息测试结果原始SQL:SELECT*FROMUSERWHEREid=?和名字=?替换SQL:SELECT*FROMUSERWHEREid=1ANDname='谢继飞'谢继飞北京。大兴区。通明湖公园准备好了,这样我们就可以拦截可以复制执行的SQL语句。下面我们来做IDEAPlugin的处理。3.通过插件开发引入探针Jar。段代码增强Jar包,复制到IDEAPlugin插件开发模块中的libs(可以自己创建),然后加载实现fileTree(dir:'libs',includes:['*jar'])在plugin.xml配置中,这样就可以在程序中找到这个jar包,在程序中进行配置。3.1复制jar到libs3.2build.gradle配置加载依赖{implementationfileTree(dir:'libs',includes:['*jar'])}介绍通过implementationfileTree加载文件树的方式,将我们配置好的Jar加载到程序中跑步。3.3程序中引入javaagentcn.bugstack.guide.idea.plugin.PerRunpublicclassPerRunextendsJavaProgramPatcher{@OverridepublicvoidpatchJavaParameters(Executorexecutor,RunProfileconfiguration,JavaParametersjavaParameters){RunConfigurationrunConfiguration=(RunConfiguration)configuration;ParametersListvmParametersList=javaParameters.getVMParametersList();vmParametersList.addParametersString("-javaagent:"+agentCoreJarPath);vmParametersList.addNotEmptyProperty("guide-idea-plugin-probe.projectId",runConfiguration.getProject().getLocationHash());}}通过继承JavaProgramPatcher类,实现patchJavaParameters方法,通过配置属性配置我们自己需要加载的-javaagent包。这样,当通过IDEA安装好插件,运行代码后,就会执行拦截打印SQL的功能。3.4plugin.xml添加配置
