您的位置:首页 > 编程语言 > Java开发

javaagent demo程序(使用javaagent实现字节码层面的代码修改)

2017-12-27 23:56 701 查看

javaagent demo程序(使用javaagent实现字节码层面的代码修改)

本文主要讲解一下内容:
1、javaagent的作用。
2、一个可用的javaagent demo程序。
3、引出类似的工具bytebuddy和asm。

好,下面上货。
一、首先说一下javaagent 的作用。javaagent是一种能够在不影响正常编译的情况下,修改字节码。java作为一种强类型的语言,不通过编译就不能能够进行jar包的生成。而有了javaagent技术,就可以在字节码这个层面对类和方法进行修改。同时,也可以把javaagent理解成一种代码注入的方式。但是这种注入比起spring的aop更加的优美。

二、一个javaagent demo程序
1、首先创建agent。作为agent的jar包必须有两个要求。
一个是必须实现premain方法,另一个是必须在MANIFEST.MF文件中有Premain-Class。
先看一下agent的实现。
package com.xueyou.demo.agent;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class FirstAgent implements ClassFileTransformer {
public final String injectedClassName = "com.xueyou.agentdemo.App";
public final String methodName = "hello";

public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
className = className.replace("/", ".");
//        System.out.println(className);
if (className.equals(injectedClassName)) {
CtClass ctclass = null;
try {
ctclass = ClassPool.getDefault().get(className);// 使用全称,用于取得字节码类<使用javassist>
CtMethod ctmethod = ctclass.getDeclaredMethod(methodName);// 得到这方法实例
ctmethod.insertBefore("System.out.println(11111111);");
return ctclass.toBytecode();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
return null;
}
}


然后需要在premain中对这个FirstAgent进行加载,具体代码如下:
package com.xueyou.demo;

import com.xueyou.demo.agent.FirstAgent;

import java.lang.instrument.Instrumentation;

/**
* Hello world!
*/
public class App {
public static void premain(String agentOps, Instrumentation inst) {
System.out.println("=========premain方法执行========");
System.out.println(agentOps);
// 添加Transformer
inst.addTransformer(new FirstAgent());
}
}


下面比较重要的是pom文件中如何对jar包进行build,因为需要自动的在MANIFEST.MF文件中添加Premain-Class,所以这里需要在pom中添加插件并且指定premain-class。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Premain-Class>com.xueyou.demo.App</Premain-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>


这样打包之后能够在jar包内看到对应的premain-class。
Manifest-Version: 1.0
Premain-Class: com.xueyou.demo.App
Archiver-Version: Plexus Archiver
Built-By: wuxueyou
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_101


2、现在我们编写这个FirstAgent要拦截的类(也可以说是要加强的类)
package com.xueyou.agentdemo;

/**
* Hello world!
*/
public class App {
public static void main(String[] args) {
hello();
}

public static void hello() {
System.out.println("this is agent-demo output");
}
}


3、编写好程序后,在运行的时候需要指定javaagent。
这里有两种方式指定javaagent:
1)使用命令行:java -javaagent:XXX.jar  ddd.jar
2)使用idea的vm option选项。



这里需要配置的就是-javaagent:agent-1.0.-SNAPSHOT.jar即可。

4、运行查看结果:



三、虽然javaagent可以完成对类的拦截和增强,但是在使用的时候还是有些困难,需要一直中string的方式进行代码的编写,而且调试的时候也不是很方便。所以,如果允许的话,可以使用bytebuddy和asm。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐