BTrace二三事之一:类转换方式和子类的匹配

以下基于BTrace1.2.2
[url]http://kenai.com/projects/btrace/downloads/directory/releases
[/url]

BTrace类的增强分两部分:

Agent载入之前已加载类的转换;
Agent载入之后新定义类的转换;

其中,Agent载入之前已加载类的转换在:
com.sun.btrace.agent.Main.handleNewClient(final Client client)方法中处理;

关键的处理步骤:

// 注册类转换器---即:ClassFileTransformer
client.registerTransformer();

// 获取所有已加载的类
Class[] classes = inst.getAllLoadedClasses();

// 对所有已加载的类进行过滤,挑选出BTrace脚本需要跟踪的类,
// 对于“+”标识的类,通过递归superClass和superInterfaces查找
if(client.isCandidate(c))list.add(c);

// 重转换已加载的需要跟踪的类---会导致之前注册的类转换器被调用,从而实现类的增强
inst.retransformClasses(classes);


~~~~~~~~~~~~~~
Agent载入之后新定义类的转换机制:

新定义的类的转换,当类被加载时,会自动触发ClassFileTransformer,从而实现类的转换。

这儿的难点是:如何实现“+”:即子类的查找匹配;
@OnMethod(clazz = "+my.Command", method = "execute")

原因是:我们知道ClassFileTransformer被触发的时机包括3种:

类定义之时:ClassLoader.defineClass();
类重定义之时:Instrumentation.redefineClasses()
类重转换之时:Instrumentation.retransformClasses(),Agent载入之前已加载类的转换就是通过这种方式实现的

而ClassLoader.defineClass()之时和后面两种时机最主要的差别是Class是否已经加载;
public byte[] transform(ClassLoader loader, final String cname, 
Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer);
即:transform方法中classBeingRedefined是否为null

我们也知道类的字节码byte[] classfileBuffer中仅仅包含直接superClass和实现接口的字符串,
而不包含间接超类和间接接口,所以仅仅凭借字节码是无从进行“+”子类的匹配判断的。
这些superClass和接口的字符串必须连接后变成真正的Class对象,才能通过递归的方式匹配查找。

为了实现“+”的查找,BTrace额外提供了一个ClassFileTransformer,这个被称作clInitTransformer,
它的作用是对所有需要加载的类,在类的静态初始化部分增加下面的代码:
{
BTraceRuntime.retransform(Ljava/lang/String;Ljava/lang/Class;)
}

以达到类被初始化后,立即发生重转换;从而再次触发ClassFileTransformer的目的。

这就是BTrace中存在两个ClassFileTransformer的原因:
void registerTransformer() {
inst.addTransformer(clInitTransformer, false);
inst.addTransformer(this, true);
}

也是hasSubclassChecks变量存在的原因。---如果有“+”存在,就强制类的重转换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值