Blog: bugstack.cn
Precipitation, share, grow, let yourself and others can gain something! 😄
One, foreword
The one-sided!
“What a great writer,” Tolstoy said on January 3, “writes only one side of himself.” How much more I, how much more we!
While we don’t write articles, we write requirements, we write code, we write comments, and when we come across a problem point that needs to be discussed, it often becomes a point of contention. This is good, that is bad, you use what what what what!
When you narrow your path, you reduce your access to new ideas, new ideas, new horizons and, very importantly, your income. Only by horizontal comparison and reference, can you have more ideas in your mind, whether in writing code, or in financial management, or in life.
Second, demand and purpose
Do you have IntelliJ IDEA in the development process, need to get the execution of SQL statement, copy out for verification, always such a statement: SELECT * FROM USER WHERE id =? AND name = ? Need to do it yourself again? What if the number is replaced by the input parameter?
Of course, this need is not that big, and you can even solve it in other ways. Then this chapter will provide you with a new way of thinking that you probably haven’t approached before.
So in the case of this chapter, we use the development ability based on IDEA Plugin to inject bytecode petting probe based on Javaagent into the code. Through the enhanced bytecode, access to com. The mysql. JDBC. PreparedStatement – > executeInternal execution object, which can directly test the SQL statement.
Case development
1. Engineering structure
Guide - idea - the plugin - the probe ├ ─ ─ the gradle ├ ─ ─ the probe - agent │ ├ ─ ─ the SRC │ │ └ ─ ─ the main │ │ └ ─ ─ Java │ │ └ ─ ─ Cn. Bugstack. Guide. Idea. The plugin │ │ ├ ─ ─ MonitorMethod. Java │ │ └ ─ ─ PreAgent. Java │ └ ─ ─ build. Gradle └ ─ ─ the probe - the plugin │ └ ─ ─ SRC │ │ └ ─ ─ the main │ │ ├ ─ ─ Java │ │ │ └ ─ ─ cn. Bugstack. Guide. Idea. The plugin │ │ │ └ ─ ─ utils │ │ │ │ └ ─ ─ PluginUtil. Java │ │ │ └ ─ ─ PerRun. Java │ │ └ ─ ─ resources │ │ └ ─ ─ meta-inf │ │ └ ─ ─ the plugin. The XML │ └ ─ ─ build. Gradle ├ ─ ─ build. Gradle └ ─ ─ gradle.propertiesCopy the code
Bugstack wormhole stack can be downloaded from the whole IDEA plug-in source code
In this IDEA plug-in project, the engineering structure is divided into two parts:
- Probe-agent: Probe module used to compile and package bytecode enhancement services for use by the probe-plugin module
- Probe-plugin: Plug-in module, passed
java.programPatcher
Load the bytecode enhancement package to get and print THE SQL statements that perform database operations.
2. Bytecode enhancement to obtain SQL
The byte-Buddy bytecode enhancement here is much simpler to use, somewhat like AOP interception, to get the information you need.
In addition, when gradle packages a build, you need to add the shadowJar module to include premain-class. You can check it out in this section of code
2.1 Probe Inlet
cn.bugstack.guide.idea.plugin.PreAgent
// The JVM first tries to call the following methods on the proxy class
public static void premain(String agentArgs, Instrumentation inst) {
AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
return builder
.method(ElementMatchers.named("executeInternal")) // Intercept any method
.intercept(MethodDelegation.to(MonitorMethod.class)); / / to entrust
};
new AgentBuilder
.Default()
.type(ElementMatchers.nameStartsWith("com.mysql.jdbc.PreparedStatement"))
.transform(transformer)
.installOn(inst);
}
Copy the code
- The byte-buddy configuration intercepts matching classes and methods, because the entire SQL statement can be retrieved from these classes and methods.
2.2 intercept SQL
cn.bugstack.guide.idea.plugin.MonitorMethod
@RuntimeType
public static Object intercept(@This Object obj, @Origin Method method, @SuperCallCallable<? > callable,@AllArguments Object... args) throws Exception {
try {
return callable.call();
} finally {
String originalSql = (String) BeanUtil.getFieldValue(obj, "originalSql");
String replaceSql = ReflectUtil.invoke(obj, "asSql");
System.out.println("Database name: Mysql");
System.out.println("Thread ID:" + Thread.currentThread().getId());
System.out.println("Time:" + new Date());
System.out.println("SQL: \r\n" + originalSql);
System.out.println("SQL: \r\n"+ replaceSql); }}Copy the code
- Intercepting method inputs are configurable operations such as
@This Object obj
To get the execution object of the current class,@Origin Method method
Is to get the execution method. - In the finally block, we can get the property information of the current class by reflection, and the SQL executed by reflection, and print it out.
2.3 Compilation and Packaging
Before testing and developing the IDEA Plugin, we need to do a packaging operation, which is to package the bytecode enhanced code into a Jar package. In the build. Gradle – > shadowJar
- After the package is compiled, you can see the Jar under build -> libs:
The probe - agent - 1.0 - the SNAPSHOT - all. Jar
This Jar is used to do bytecode enhancement.
2.4 Test and Verification
The bytecode enhancement component can be tested before being used by the plug-in to avoid having to start the plug-in each time.
Unit testing
public class ApiTest {
public static void main(String[] args) throws Exception {
String URL = "JDBC: mysql: / / 127.0.0.1:3306 / itstack? characterEncoding=utf-8";
String USER = "root";
String PASSWORD = "123456";
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
String sql="SELECT * FROM USER WHERE id = ? AND name = ?";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setLong(1.1L);
statement.setString(2."Thank you airplane.");
ResultSet rs = statement.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("name") + "" + rs.getString("address")); }}}Copy the code
- The VM options:
- javaAgent: your path \libs\ probe-agent-1.0-snapshot-all.jar
- Note that when the test runs, you need to configure VM options for ApiTest to print the intercepting SQL information
The test results
SQL: SELECT * FROM USER WHERE id =? AND name = ? Replace SQL: SELECT * FROM USER WHERE id =1 AND name = 'Thank you aeroplane'Xie Yiyi Beijing. Daxing District. Tongming Lake ParkCopy the code
- Ok, now that we can intercept SQL statements that can be copied to execute, let’s do the IDEA Plugin processing.
3. Introduce the probe Jar through plug-in development
Next, we need to develop the bytecode enhancement Jar package, copy it to the IDEA Plugin Plugin development module liBS (can create their own), and then load implementation fileTree in plugin.xml configuration (dir: ‘libs’, includes: [‘*jar’]).
3.1 Copying jars to LIBS
3.2 Build. gradle configuration loaded
dependencies {
implementation fileTree(dir: 'libs', includes: ['*jar'])
}
Copy the code
- through
implementation fileTree
Introduce the method of loading file tree, and load our configured Jar into the program run.
3.3 Introducing JavaAgent into the program
cn.bugstack.guide.idea.plugin.PerRun
public class PerRun extends JavaProgramPatcher {
@Override
public void patchJavaParameters(Executor executor, RunProfile configuration, JavaParameters javaParameters) {
RunConfiguration runConfiguration = (RunConfiguration) configuration;
ParametersList vmParametersList = javaParameters.getVMParametersList();
vmParametersList.addParametersString("-javaagent:" + agentCoreJarPath);
vmParametersList.addNotEmptyProperty("guide-idea-plugin-probe.projectId", runConfiguration.getProject().getLocationHash()); }}Copy the code
- Through inheritance
JavaProgramPatcher
Classes that implementpatchJavaParameters
Method to configure our own needs to be loaded via the Configuration property-javaagent
The package. - In this way, the interception and printing of SQL will be implemented when the code is run after the plug-in is installed through IDEA.
3.4 Plugin.xml Adds the configuration
<extensions defaultExtensionNs="com.intellij">
<! -- Add your extensions here -->
<java.programPatcher implementation="cn.bugstack.guide.idea.plugin.PerRun"/>
</extensions>
Copy the code
- Then you need to configure the developed loading classes to
java.programPatcher
This way the program can be loaded when it runs.
4. Test and verification
- Prepare a project with database operations that require JDBC,If it’s something else, you need to expand it yourself
- After starting the plug-in, open your project, run the unit tests, and view the print area
Start the plugin
- If you are new to download the code, you can run it in probe-plugin -> Tasks -> Intellij -> runIde.
Unit testing
@Test
public void test_update(a){
User user = new User();
user.setId(1L);
user.setName("Thank you airplane.");
user.setAge(18);
user.setAddress("Daxing District, Beijing. "" Yizhuang Economic Development Zone" ");
userDao.update(user);
}
Copy the code
The test results
22:30:55.593 [main] DEBUG cn.bugstack.test.demo.infrastructure.dao.UserDao.update[143] - ==> Preparing: UPDATE user SET name=? ,age=? ,address=? WHERE id=?22:30:55.625 [main] DEBUG cn.bugstack.test.demo.infrastructure.dao.UserDao.update[143] - ==> Parameters:18(Integer), Beijing, China. Daxing District. Yizhuang Economic Development Zone (String),1(Long) Mysql thread ID:1SQL: UPDATE user SET name=? ,age=? ,address=? WHERE id=? SQL: UPDATE user SET name='Thank you aeroplane',age=18,address=Daxing District, Beijing. Yizhuang Economic Development Zone '
WHERE id=1
Copy the code
- As you can see from the test results, we can get the SQL statement directly to test validation, instead of copying the SQL with question marks and having to modify the test.
Five, the summary
- First of all, we try to use the multi-module method to create a project in this chapter, which can better maintain all kinds of code modules required by a project.You can also try using Gradle to create multi-module projects
- This article is just an introduction to the use of bytecode staking enhancement, but the technology can be used in many more scenarios to develop a variety of tools to improve development efficiency.
- Know how additional Jar packages are loaded into the project and how to configure them
javaagent
Introduce our own developed probe components.
Six, series recommendation
- ASM, Javassist, Byte-Buddy, Javaagent bytecode programming content extension learning
- Scheme design: Based on IDEA plug-in development and bytecode staking technology, realize automatic analysis of r&d delivery quality
- IDEA plug-in development completed, how to release?
- Application development – level non – invasive full – link monitoring design
- Lottery Lottery System – A four-tier architecture practice based on domain-driven design