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

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。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值