0%

java插桩(javaagent)

昨天整了半天没有整出来的那个结果最后是一个包名引用错了..

在MANIFEST.MF中使用的包名和我自己的包名没有对上…

首先搬运这个师傅关于java Instrument的原理

javaagent

在maven项目里面修改pom.xml文件然后添加入build的选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestEntries>
<Project-name>javaagent</Project-name>
<Project-version>1.0</Project-version>
<Premain-Class>com.javaagent.MyAgent</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-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>

加入packing和build标签,

首先做一个MyAgent类,导入了java.lang.instrument.Instrumentation的接口

这是一个Java1.6加进来的接口,作用就是你通过jvmti代理引用程序来jvm的访问(主要用于类的动态改变和操作),这里只是将其用于一个在main函数执行之前的劫持并加载我们自己的类。

1
2
3
4
5
6
7
8
9
10
11
//src/main/java/com/javaagent/MyAgent.java
package com.javaagent;

import java.lang.instrument.Instrumentation;

public class MyAgent {
public static void premain(String args, Instrumentation instrumentation) throws Exception {
System.out.println("Hello javaagent permain:"+args);
}
}

上面这个premain方法就是Instrmentation中提供的一个方法,可以在main运行前先运行premain函数里面的内容。

接下来定义新一个新的类用来执行main函数

1
2
3
4
5
6
7
//src/test/java/MyAgentTest.java
public class MyAgentTest {
public static void main(String[] args) {
System.out.println("main");
}
}

编辑一下MANIFEST.MF文件

在这个函数中需要定义好一个Premain-Class选项,这个用于定位刚刚写的MyAgent那个包含了Premain函数的类(就是包中类的位置),配置项填错就没法运行。

然后使用maven build这个package

最后配置vm options来添加一个javaagent在启动时添加参数

-javaagent:这里是之前package打包出来的jar包路径.jar=1

后面的参数1是premain函数接收的参数args。

最后运行这个MyAgentTest.java

使用ByteBuddy构建一个java Agent

只需要加依赖然后修改一下就好,添加两个依赖,和之前文章一样先导入ByteBuddy

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.12.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy-agent -->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.12.2</version>
<scope>test</scope>
</dependency>

重写premain方法

官方教程给的使用ByteBuddy创建一个java Agent的方法

创建 Java Agents

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ToStringAgent {
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(isAnnotatedWith(ToString.class))
.transform(new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder transform(DynamicType.Builder builder,
TypeDescription typeDescription,
ClassLoader classloader) {
return builder.method(named("toString"))
.intercept(FixedValue.value("transformed"));
}
}).installOn(instrumentation);
}
}

然后根据这个形式去写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.javaagent;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

public class MyAgent {
public static void premain(String args, Instrumentation instrumentation) throws Exception {
// System.out.println("Hello javaagent permain:"+args);
System.out.println("this is an perform monitor agent.");

AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
return builder
.method(ElementMatchers.<MethodDescription>any()) // 拦截任意方法
.intercept(MethodDelegation.to(TimeInterceptor.class)); // 委托
}

};

AgentBuilder.Listener listener = new AgentBuilder.Listener() {
@Override
public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {

}

@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {

}

@Override
public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded) {

}

@Override
public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) {

}

@Override
public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {

}
};

new AgentBuilder
.Default()
.type(ElementMatchers.nameStartsWith("com.javaagent.MyAgentTest")) // 指定需要拦截的类
.transform(transformer)
.with(listener)
.installOn(instrumentation);
}

}


实现委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.javaagent;

import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class TimeInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method,
@SuperCall Callable<?> callable) throws Exception {
long start = System.currentTimeMillis();
try {
// 原有函数执行
return callable.call();
} finally {
System.out.println(method + ": took " + (System.currentTimeMillis() - start) + "ms");
}
}
}

MyAgentTest进行调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.javaagent;

public class MyAgentTest {
// public static void main(String[] args) {
// System.out.println("main");
// }
private void fun1() throws Exception {
System.out.println("this is fun 1.");
Thread.sleep(500);
}

private void fun2() throws Exception {
System.out.println("this is fun 2.");
Thread.sleep(500);
}

// -javaagent:这里依旧是包的路径/javaagent-1.0-SNAPSHOT.jar
public static void main(String[] args) throws Exception {
MyAgentTest test = new MyAgentTest();
test.fun1();
test.fun2();

}
}

​ 同样先build然后在进行运行

参考

http://www.jinyunlong.xyz/articles/2021/05/15/1621089190040.html

https://www.cnblogs.com/tr1ple/p/12709402.html

https://github.com/hawkingfoo/demo-agent

http://rui0.cn/archives/1063

http://www.noobyard.com/article/p-smvzgpzs-dh.html