谁动了他的jar包(三)


谁动了他的jar包(一) [url]http://ilab.iteye.com/blog/984823[/url]
谁动了他的jar包(二) [url]http://ilab.iteye.com/blog/1002629[/url]

一的方法侵入性较强,可维护性较差.
二的方法逻辑分工明确,维护性较好,使用起来简单.但无法适用所有的修改情况;
对于不同情况的类,要进行不同的反射改造,和继承.
特别的,对于,final标识的属性或者类来说,二的方法,就无能为力了.

有没有两全其美的方法呢,既可以做到无侵入,易维护,并且可以适用于所有不同的情况,达到完美的替换,以达到修改jar包的目的呢;

可以试试,用jvmti~.

[b]先简单介绍下[/b]
[url]http://download.oracle.com/javase/1.5.0/docs/guide/jvmti/[/url]

偷个懒,直接翻译了 :)


[i]jvm 工具接口(jvmti) 是一种新的本地编程工具接口.
通过它,你可以对虚拟机中的程序进行监控,[b]也能够控制其执行[/b];
jvmti 支持了所有的需要访问虚拟机状态的工具,
包括,但不仅限于: 分析,调试(debug),监控,线程分析,覆盖分析工具;

jvmti 用来替代 jvmpi及jvmdi(原来的分析调试工具);[/i]

[b]"控制其执行",是否包括,改变某些类的执行方式呢.答案是肯定的,我们现在仍然用上面的例子,
来演示下如何用jvmti的技术,来达到我们的目的;[/b]

新建类Transformer,实现 java.lang.instrument.ClassFileTransformer
public class Transformer implements ClassFileTransformer {

public static Properties transferClass = new Properties();
static {
transferClass.put("Feature", "Feature.class");
}

// 获取我们指定的想要的类的原代码,这里的代码很偷懒...具体怎么获取可以根据场景而定
public static byte[] getBytesFromFile(String target) {
try {
System.out.println("start replacing");
InputStream is = new FileInputStream(new File("D:/" + target));
// bytes空间大于目标类即可,这里只做简单演示;完整的处理,可能需要做循环读取数据到bytes;
byte[] bytes = new byte[1024 * 1024];
int length = is.read(bytes);
byte[] rs = new byte[length];
System.arraycopy(bytes, 0, rs, 0, length);
is.close();
return rs;
} catch (Exception e) {
System.out.println("error occurs in _ClassTransformer!" + e.getClass().getName());
e.printStackTrace();
return null;
}
}

public byte[] transform(ClassLoader l, String className, Class<?> c, ProtectionDomain pd, byte[] b)
throws IllegalClassFormatException {
String temp = transferClass.getProperty(className);
if (temp != null && temp.length() > 0) {
System.out.println("stealing : " + className);
return Transformer.getBytesFromFile(temp);
}
return null;
}

}


以及类Premain
public class Premain {

public static void premain(String agentArgs, Instrumentation inst) throws ClassNotFoundException,
UnmodifiableClassException {
inst.addTransformer(new Transformer());
}
}


打成jar包premain.jar,修改\META-INF\MANIFEST.MF

Manifest-Version: 1.0
Class-Path: .
Premain-Class: Premain



这样,我们就简单完成了一个类代理的小工具;
该工具的作用是,监控jvm所有加载的类,当该类是在transferClass中配置有存在时,从D盘读取.class文件进行替换;


[b]我们来试下功能:)[/b]

修改Feature
public class Feature {

private String content;

public Feature(){
this.content = "hello kitty";
}

public void show() {
System.out.println(this.content);
}
}

将.class文件放在D:盘根目录 ,将premain.jar包也放在根目录
此时再将Feature改回来
public class Feature {

private String content;

public void show() {
System.out.println(this.content);
}
}


执行

public class Test {

public static void main(String[] args) throws Exception {
Function function = new Function();
function.show();
}
}


输出, 为 null

嗯是的,因为没加参数
设置runConfigration VMargument 为 [b]-javaagent:D:/premain.jar[/b]


然后,再跑下?

输出,

stealing : Feature
start replacing
hello kitty


:)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值