Skip to content

Commit f83a9e6

Browse files
committed
support new instrument/define config format
1 parent fd7c477 commit f83a9e6

File tree

6 files changed

+311
-15
lines changed

6 files changed

+311
-15
lines changed

bytekit-core/src/main/java/com/alibaba/bytekit/asm/instrument/InstrumentConfig.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.alibaba.bytekit.asm.instrument;
22

3+
import java.util.ArrayList;
4+
import java.util.List;
5+
36
import com.alibaba.bytekit.asm.matcher.ClassMatcher;
47
import com.alibaba.deps.org.objectweb.asm.tree.ClassNode;
58

@@ -29,6 +32,11 @@ public class InstrumentConfig {
2932
*/
3033
private boolean triggerRetransform = false;
3134

35+
/**
36+
* 与这个 instrument 配置关联的 define 类列表,只有当这个 instrument 匹配时才会 define 这些类
37+
*/
38+
private List<DefineConfig> defineConfigs = new ArrayList<DefineConfig>();
39+
3240
public InstrumentConfig(ClassNode instrumentClassNode, ClassMatcher classMatcher) {
3341
this(instrumentClassNode, classMatcher, false, false);
3442
}
@@ -73,4 +81,16 @@ public void setTriggerRetransform(boolean triggerRetransform) {
7381
this.triggerRetransform = triggerRetransform;
7482
}
7583

84+
public List<DefineConfig> getDefineConfigs() {
85+
return defineConfigs;
86+
}
87+
88+
public void setDefineConfigs(List<DefineConfig> defineConfigs) {
89+
this.defineConfigs = defineConfigs;
90+
}
91+
92+
public void addDefineConfig(DefineConfig defineConfig) {
93+
this.defineConfigs.add(defineConfig);
94+
}
95+
7696
}

bytekit-core/src/main/java/com/alibaba/bytekit/asm/instrument/InstrumentParseResult.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,16 @@ public class InstrumentParseResult {
1212

1313
private List<InstrumentConfig> instrumentConfigs = new ArrayList<InstrumentConfig>();
1414

15+
/**
16+
* @deprecated 已废弃,define 配置现在关联到具体的 InstrumentConfig 上。为了保持向后兼容暂时保留。
17+
*/
18+
@Deprecated
1519
private List<DefineConfig> defineConfigs = new ArrayList<DefineConfig>();
1620

21+
/**
22+
* @deprecated 已废弃,建议使用关联到 InstrumentConfig 的 define 配置
23+
*/
24+
@Deprecated
1725
public void addDefineClass(String className, byte[] classBytes) {
1826
this.defineConfigs.add(new DefineConfig(classBytes, className));
1927
}
@@ -30,10 +38,18 @@ public void setInstrumentConfigs(List<InstrumentConfig> instrumentConfigs) {
3038
this.instrumentConfigs = instrumentConfigs;
3139
}
3240

41+
/**
42+
* @deprecated 已废弃,define 配置现在关联到具体的 InstrumentConfig 上
43+
*/
44+
@Deprecated
3345
public List<DefineConfig> getDefineConfigs() {
3446
return defineConfigs;
3547
}
3648

49+
/**
50+
* @deprecated 已废弃,define 配置现在关联到具体的 InstrumentConfig 上
51+
*/
52+
@Deprecated
3753
public void setDefineConfigs(List<DefineConfig> defineConfigs) {
3854
this.defineConfigs = defineConfigs;
3955
}

bytekit-core/src/main/java/com/alibaba/bytekit/asm/instrument/InstrumentTemplate.java

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import java.lang.instrument.Instrumentation;
77
import java.util.ArrayList;
88
import java.util.Collection;
9+
import java.util.HashMap;
910
import java.util.List;
11+
import java.util.Map;
1012
import java.util.Properties;
1113
import java.util.jar.JarEntry;
1214
import java.util.jar.JarFile;
@@ -85,14 +87,47 @@ public InstrumentParseResult build() throws IOException {
8587
InputStream inputStream = jarFile.getInputStream(propertiesEntry);
8688
Properties properties = PropertiesUtils.loadNotNull(inputStream);
8789

88-
String triggerRetransformValue = properties.getProperty("triggerRetransform", "false"); // 使用默认值避免null值
90+
String triggerRetransformValue = properties.getProperty("triggerRetransform", "false");
8991
boolean triggerRetransform = Boolean.parseBoolean(triggerRetransformValue);
90-
for (Pair<String, byte[]> pair : readClassBytes(properties, INSTRUMENT, jarFile)) {
91-
parse(result, pair.second, triggerRetransform);
92+
93+
// 解析新格式:instrument.{key}=... 和 define.{key}=...
94+
Map<String, List<Pair<String, byte[]>>> instrumentMap = new HashMap<String, List<Pair<String, byte[]>>>();
95+
Map<String, List<Pair<String, byte[]>>> defineMap = new HashMap<String, List<Pair<String, byte[]>>>();
96+
97+
for (String key : properties.stringPropertyNames()) {
98+
if (key.startsWith("instrument.")) {
99+
String configKey = key.substring("instrument.".length());
100+
List<Pair<String, byte[]>> classBytesList = readClassBytes(properties, key, jarFile);
101+
if (!classBytesList.isEmpty()) {
102+
instrumentMap.put(configKey, classBytesList);
103+
}
104+
} else if (key.startsWith("define.")) {
105+
String configKey = key.substring("define.".length());
106+
List<Pair<String, byte[]>> classBytesList = readClassBytes(properties, key, jarFile);
107+
if (!classBytesList.isEmpty()) {
108+
defineMap.put(configKey, classBytesList);
109+
}
110+
} else if (key.equals(INSTRUMENT)) {
111+
// 兼容旧格式:instrument=...
112+
for (Pair<String, byte[]> pair : readClassBytes(properties, INSTRUMENT, jarFile)) {
113+
parse(result, pair.second, triggerRetransform, null);
114+
}
115+
} else if (key.equals(DEFINE)) {
116+
// 兼容旧格式:define=...(全局 define,会被添加到所有 instrument)
117+
for (Pair<String, byte[]> pair : readClassBytes(properties, DEFINE, jarFile)) {
118+
result.addDefineClass(pair.first, pair.second);
119+
}
120+
}
92121
}
93-
94-
for (Pair<String, byte[]> pair : readClassBytes(properties, DEFINE, jarFile)) {
95-
result.addDefineClass(pair.first, pair.second);
122+
123+
// 处理新格式的 instrument 和 define 关联
124+
for (Map.Entry<String, List<Pair<String, byte[]>>> entry : instrumentMap.entrySet()) {
125+
String configKey = entry.getKey();
126+
List<Pair<String, byte[]>> defineClassList = defineMap.get(configKey);
127+
128+
for (Pair<String, byte[]> instrumentPair : entry.getValue()) {
129+
parse(result, instrumentPair.second, triggerRetransform, defineClassList);
130+
}
96131
}
97132
}
98133

@@ -103,7 +138,7 @@ public InstrumentParseResult build() throws IOException {
103138

104139
// 处理单独设置 byte[]
105140
for (byte[] classBytes : instrumentClassList) {
106-
parse(result, classBytes, false);
141+
parse(result, classBytes, false, null);
107142
}
108143

109144
return result;
@@ -137,7 +172,7 @@ private List<Pair<String, byte[]>> readClassBytes(Properties properties, String
137172
return result;
138173
}
139174

140-
private void parse(InstrumentParseResult result, byte[] classBytes, boolean triggerRetransform) {
175+
private void parse(InstrumentParseResult result, byte[] classBytes, boolean triggerRetransform, List<Pair<String, byte[]>> defineClassList) {
141176
ClassNode classNode = AsmUtils.toClassNode(classBytes);
142177

143178
if (!AsmUtils.fitCurrentJvmMajorVersion(classNode)) {
@@ -158,28 +193,45 @@ private void parse(InstrumentParseResult result, byte[] classBytes, boolean trig
158193

159194
if (matchClassList != null && !matchClassList.isEmpty()) {
160195
SimpleClassMatcher classMatcher = new SimpleClassMatcher(matchClassList);
161-
result.addInstrumentConfig(new InstrumentConfig(classNode, classMatcher, updateMajorVersion, triggerRetransform));
196+
InstrumentConfig config = new InstrumentConfig(classNode, classMatcher, updateMajorVersion, triggerRetransform);
197+
addDefineConfigs(config, defineClassList);
198+
result.addInstrumentConfig(config);
162199
}
163200

164201
List<String> matchSuperclassList = AsmAnnotationUtils.queryAnnotationArrayValue(classNode.visibleAnnotations,
165202
Type.getDescriptor(Instrument.class), "Superclass");
166203

167204
if (!matchSuperclassList.isEmpty()) {
168205
SimpleSubclassMatcher matcher = new SimpleSubclassMatcher(matchSuperclassList);
169-
result.addInstrumentConfig(new InstrumentConfig(classNode, matcher, updateMajorVersion, triggerRetransform));
206+
InstrumentConfig config = new InstrumentConfig(classNode, matcher, updateMajorVersion, triggerRetransform);
207+
addDefineConfigs(config, defineClassList);
208+
result.addInstrumentConfig(config);
170209
}
171210

172211
List<String> matchInterfaceList = AsmAnnotationUtils.queryAnnotationArrayValue(classNode.visibleAnnotations,
173212
Type.getDescriptor(Instrument.class), "Interface");
174213

175214
if (!matchInterfaceList.isEmpty()) {
176215
SimpleInterfaceMatcher matcher = new SimpleInterfaceMatcher(matchInterfaceList);
177-
result.addInstrumentConfig(new InstrumentConfig(classNode, matcher, updateMajorVersion, triggerRetransform));
216+
InstrumentConfig config = new InstrumentConfig(classNode, matcher, updateMajorVersion, triggerRetransform);
217+
addDefineConfigs(config, defineClassList);
218+
result.addInstrumentConfig(config);
178219
}
179220

180221
// TODO 处理 @NewField
181222
}
182223

224+
/**
225+
* 将 define 类列表添加到 InstrumentConfig
226+
*/
227+
private void addDefineConfigs(InstrumentConfig config, List<Pair<String, byte[]>> defineClassList) {
228+
if (defineClassList != null && !defineClassList.isEmpty()) {
229+
for (Pair<String, byte[]> pair : defineClassList) {
230+
config.addDefineConfig(new DefineConfig(pair.second, pair.first));
231+
}
232+
}
233+
}
234+
183235
public static List<Class<?>> matchedClass(Instrumentation instrumentation, InstrumentConfig instrumentConfig) {
184236
List<Class<?>> result = new ArrayList<Class<?>>();
185237

bytekit-core/src/main/java/com/alibaba/bytekit/asm/instrument/InstrumentTransformer.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.lang.instrument.ClassFileTransformer;
44
import java.lang.instrument.IllegalClassFormatException;
55
import java.security.ProtectionDomain;
6+
import java.util.ArrayList;
67
import java.util.List;
78

89
import com.alibaba.bytekit.asm.inst.impl.InstrumentImpl;
@@ -97,8 +98,23 @@ public byte[] transform(ClassLoader loader, String className, Class<?> classBein
9798
if (targetClassNode != null) {
9899
// TODO 支持 bootstrap classloader?
99100
if (loader != null) {
100-
List<DefineConfig> defineConfigs = instrumentParseResult.getDefineConfigs();
101-
for (DefineConfig defineConfig : defineConfigs) {
101+
// 收集所有匹配的 instrument config 关联的 define 类
102+
List<DefineConfig> allDefineConfigs = new ArrayList<DefineConfig>();
103+
for (InstrumentConfig config : instrumentConfigs) {
104+
if (config.getClassMatcher().match(loader, className, classBeingRedefined, protectionDomain,
105+
classfileBuffer)) {
106+
allDefineConfigs.addAll(config.getDefineConfigs());
107+
}
108+
}
109+
110+
// 兼容旧格式:添加全局的 define 配置(已废弃)
111+
List<DefineConfig> globalDefineConfigs = instrumentParseResult.getDefineConfigs();
112+
if (globalDefineConfigs != null && !globalDefineConfigs.isEmpty()) {
113+
allDefineConfigs.addAll(globalDefineConfigs);
114+
}
115+
116+
// 定义所有关联的类
117+
for (DefineConfig defineConfig : allDefineConfigs) {
102118
try {
103119
ReflectUtils.defineClass(defineConfig.getClassName(), defineConfig.getClassBytes(), loader);
104120
} catch (Throwable e) {

0 commit comments

Comments
 (0)