Java Language
जावा एजेंट
खोज…
एजेंटों के साथ कक्षाएं संशोधित करना
सबसे पहले, सुनिश्चित करें कि उपयोग किए जा रहे एजेंट में निम्न विशेषताएं हैं।
Can-Redefine-Classes: true
Can-Retransform-Classes: true
जावा एजेंट शुरू करने से एजेंट को क्लास इंस्ट्रूमेंटेशन तक पहुंचने दिया जाएगा। इंस्ट्रूमेंटेशन के साथ आप addTransformer (ClassFileTransformer ट्रांसफार्मर) कह सकते हैं। ClassFileTransformers आपको कक्षाओं के बाइट्स को फिर से लिखने देगा। कक्षा में केवल एक ही विधि होती है जो ClassLoader की आपूर्ति करती है जो वर्ग को लोड करती है, वर्ग का नाम, एक java.lang.Class इसका उदाहरण, यह प्रोटेक्शनडोमैन है, और अंतिम रूप से कक्षा का बाइट्स है।
यह इस तरह दिख रहा है:
byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
शुद्ध रूप से बाइट्स से एक वर्ग को संशोधित करने में उम्र लग सकती है। इसे मापने के लिए पुस्तकालय हैं जिनका उपयोग कक्षा बाइट्स को कुछ अधिक उपयोगी बनाने के लिए किया जा सकता है।
इस उदाहरण में मैं ASM का उपयोग करूंगा, लेकिन अन्य विकल्पों जैसे कि Javassist और BCEL में समान विशेषताएं हैं।
ClassNode getNode(byte[] bytes) {
// Create a ClassReader that will parse the byte array into a ClassNode
ClassReader cr = new ClassReader(bytes);
ClassNode cn = new ClassNode();
try {
// This populates the ClassNode
cr.accept(cn, ClassReader.EXPAND_FRAMES);
cr = null;
} catch (Exception e) {
e.printStackTrace();
}
return cn;
}
यहां से क्लासनॉड ऑब्जेक्ट में परिवर्तन किया जा सकता है। यह बदलते क्षेत्र / विधि का उपयोग अविश्वसनीय रूप से आसान बनाता है। इसके अलावा ASM के ट्री एपीआई के तरीकों के bytecode को संशोधित करना एक हवा है।
एक बार सम्पादन समाप्त होने के बाद आप क्लासनोड को निम्न विधि से बाइट्स में बदल सकते हैं और उन्हें रूपांतरण विधि में वापस कर सकते हैं:
public static byte[] getNodeBytes(ClassNode cn, boolean useMaxs) {
ClassWriter cw = new ClassWriter(useMaxs ? ClassWriter.COMPUTE_MAXS : ClassWriter.COMPUTE_FRAMES);
cn.accept(cw);
byte[] b = cw.toByteArray();
return b;
}
रनटाइम पर एक एजेंट जोड़ना
एजेंटों को रनटाइम पर एक जेवीएम में जोड़ा जा सकता है। एक एजेंट को लोड करने के लिए आपको अटैच एपीआई के VirtualMachine.attatch (स्ट्रिंग आईडी) का उपयोग करना होगा । आप फिर निम्न विधि से संकलित एजेंट जार लोड कर सकते हैं:
public static void loadAgent(String agentPath) {
String vmName = ManagementFactory.getRuntimeMXBean().getName();
int index = vmName.indexOf('@');
String pid = vmName.substring(0, index);
try {
File agentFile = new File(agentPath);
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent(agentFile.getAbsolutePath(), "");
VirtualMachine.attach(vm.id());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
यह लोडेड एजेंट में प्रीमैन ((स्ट्रींग एजेंटआर्गेस, इंस्ट्रूमेंटेशन इंस्टेंस) को कॉल नहीं करेगा, बल्कि एजेंटमैन (स्ट्रिंग एजेंटएरग्स, इंस्ट्रूमेंटेशन इंस्टेंस) को कॉल करेगा। इसके लिए एजेंट्स -क्लास को एजेंट्स मैनटेस्ट.एमएफ में सेट करना होगा।
एक बुनियादी एजेंट की स्थापना
प्रीमैन वर्ग में "प्रीमैन (स्ट्रिंग एजेंटअर्ज़ इंस्ट्रूमेंटेशन इंस्टेंस)" विधि शामिल होगी।
यहाँ एक उदाहरण है:
import java.lang.instrument.Instrumentation;
public class PremainExample {
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println(agentArgs);
}
}
जब जार फ़ाइल में संकलित किया जाता है तो मेनिफेस्ट खोलें और यह सुनिश्चित करें कि इसमें प्रीमैन-क्लास विशेषता है।
यहाँ एक उदाहरण है:
Premain-Class: PremainExample
एक और जावा प्रोग्राम "मायप्रोग्राम" के साथ एजेंट का उपयोग करने के लिए आपको एजेंट को जेवीएम तर्कों में परिभाषित करना होगा:
java -javaagent:PremainAgent.jar -jar myProgram.jar