# Preface
In the previous quest for Java thermal deployment, we implemented thermal deployment by repeatedly loading the ClassLoader and Class files in a dead loop, but we also pointed out the shortcomings-----inflexible. You need to manually modify files and so on.
If there is a function, when you need to reload the class and modify the class, there is a converter to automatically help you modify the existing class file into the class file you set, then you do not need to manually modify the compilation.
Perhaps the first thing you think of is a fuss in the custom ClassLoader, like in LoadClass, after you get the bytecode, modify the bytecode by ASM or javassist, and then call the DefineClass method.
Yes, but this intrusion is too great. If the JVM provides something like a "class converter" at the bottom, is it not intrusive?
In fact, the JVM does provide us with a tool that is today's protagonist------the Java agent.
1. What is a Java agent
In JDK 1.5, Java introduced the Java.lang.Instrument package, which provides tools to help developers dynamically modify the Class type in the system while the Java program is running. One of the key components of using the package is the Java agent. From the name, it seems to be a Java proxy, and in fact, his function is more like a class type of converter, he can accept the re-external request at runtime, modify the class type.
If you execute Java commands at the command line, some command help appears, with the options for the Java agent:
2. Java Agent Detailed description
The parameter javaagent can be used to specify a jar package, and there are 2 requirements for the Java package:
- The MANIFEST.MF file for this jar package must specify the Premain-class entry.
- The class specified by Premain-class must implement the Premain () method.
The focus is on the Premain method, which is our title today. Literally, it is the class that runs before the main function. When the Java virtual machine starts, before executing the main function, the JVM will first run the Premain method of the Premain-class class in the jar package specified by-javaagent, where the method can be signed as follows:
1.public static void Premain (String Agentargs, Instrumentation Inst)
2.public static void Premain (String Agentargs)
The JVM will first load the 1 signature method, the load succeeds ignoring 2, and if 1 is not, load the 2 method. This logic is in the Sun.instrument.InstrumentationImpl class:
Parameters Agentargs by the command line to the Java Agent parameters, Inst is the Java Class Bytecode conversion tool, instrumentation Common methods are as follows:
void Addtransformer (Classfiletransformer transformer, Boolean canretransform);
Add a class file converter to change the class binary stream data, parameter Canretransform set whether to allow re-conversion.
void redefineclasses (classdefinition ... definitions) hrows ClassNotFoundException, unmodifiableclassexception;
Before the class is loaded, the class file is redefined and classdefinition represents a new definition of a class that needs to be redefined with the Retransformclasses method after the class is loaded.
Boolean Removetransformer (Classfiletransformer transformer);
Delete a class converter
void Retransformclasses (CLASS<?> .... classes) throws Unmodifiableclassexception
After the class is loaded, redefine the class. This is important, the method is added after 1.6, in fact, the method is an update of a class.
3. How do I use it?
Using javaagent requires several steps:
- Defines a MANIFEST. MF file, the Premain-class option must be included, and the can-redefine-classes and can-retransform-classes options are often added.
- Creates a premain-class specified class that contains the Premain method, which is determined by the user itself.
- The classes and MANIFEST that will be premain. MF file into a jar package.
- Use the parameter-javaagent:/jar package path =[agentargs parameter] to start the method that you want to proxy.
After performing the above steps, the JVM executes the Premain method first, and most of the class loads pass through the method, noting that the majority, not all. Of course, the main omission is the system class, because many system classes are performed before the agent, and the user class loading is bound to be intercepted.
In other words, this method intercepts the load activity of most classes before the Main method is started, note: Before the class is loaded. In other words, we can do many articles in this gap, such as modifying bytecode.
Let's try it out:
1 First define a MANIFEST. MF file:
Manifest-Version: 1.0Can-Redefine-Classes: trueCan-Retransform-Classes: truePremain-Class: cn.think.in.java.clazz.loader.asm.agent.PreMainTraceAgent
- Creates a premain-class specified class that contains the Premain method:
"' Java
public class Premaintraceagent {
public static void Premain (String Agentargs, Instrumentation inst) {
System.out.println ("Agentargs:" + Agentargs);
Inst.addtransformer (New Classfiletransformer () {
@Override
Public byte[] Transform (ClassLoader loader, String className, class<?> classbeingredefined,
Protectiondomain Protectiondomain, byte[] classfilebuffer)
Throws Illegalclassformatexception {
System.out.println ("Premain load Class:" + className);
return classfilebuffer;
}
}, True);
}
}
````
The classes and MANIFEST that will be premain. MF file into a jar package.
Using the idea build, of course you can also use Maven. Please google for details.
Use the parameter-javaagent:/jar package path =[agentargs parameter] to start the method that you want to proxy.
We certainly need a test class:
class AccountMain { publicstaticvoidmain(String[] args) throws ClassNotFoundException, InterruptedException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { while (true) { newAccount(); account.operation(); } }}class Account { publicvoidoperation() { System.out.println("operation...."); }}
VM Parameters-javaagent:/jar Package path =[agentargs parameters].
Operation Result:
As you can see, our Premain method is actually called before the Main method and is called when the class is loaded, and the Classfilebuffer parameter of the transform method that we override is the byte code that is about to be loaded into the virtual machine, so We can use various bytecode libraries to make modifications. Specific changes, here is not the table, and later have the opportunity to write well.
4. What is the relationship to thermal deployment?
Having said this, the Java agent can do proxies at the same time as the main method and load bytecode, somewhat like AOP. But what does it have to do with hot deployment?
Memories just started we said, if we customize a class loader, then we can reload the class (The new class loader) when the bytecode modified, but the business code is more intrusive, if at the bottom, that is, the JVM level, when the bytecode is loaded back to a method, Is it not our intention to modify the bytecode in this method?
Let's look at the Premain method:
Public Static void Premain(String Agentargs, Instrumentation Inst) {System. out.println("Agentargs:"+ Agentargs); Inst.Addtransformer(NewClassfiletransformer () {@Override Public byte[]Transform(ClassLoader loader, String className, class<?> classbeingredefined, Protectiondomain Protectiondomain,byte[] classfilebuffer)throwsillegalclassformatexception {System. out.println("Premain load Class:"+ ClassName);returnClassfilebuffer; } },true); }
The instrumentation in this method adds a class converter, which is long-term and valid, and when the converter is added, it will be intercepted whenever there is a class-loaded activity. Suppose that our business is when a class needs to be modified, we reload (re-create the class loader premise) The original bytecode, after loading, note: The bytecode is modified after loading. These operations are completely transparent to the business code and are largely non-intrusive (with VM parameters added).
Summarize
Through the above steps, we will explore the Java thermal deployment of the code is optimized, originally directly manually modified bytecode, now by loading the original bytecode, the original bytecode based on the modification, and then reload, completed a hot deployment.
And it all benefits from the Java agent, although the use of custom class loading can be done, but it seems not very elegant. The use of Java Agent allows the modification of bytecode this action is invisible, transparent to the business, reduce intrusion.
In fact, Premain still has shortcomings. What shortcomings? Even more command lines and arguments? Can you not add parameters? OK! Java 1.6 has already prepared this tool for us. That is, Agentmain, you can modify a class without any parameters, and you don't even need to recreate the ClassLoader! Is it magical? We say that a class loader can only load a class, and to modify a class, you must recreate a new ClassLoader. However, the JVM does a lot for us, and he modifies the class definition directly at the bottom. So we don't have to recreate the class loader. We'll cover this in more detail in the next article.
Good luck!!!!!
Quest Java Hot Deployment II (Java Agent Premain)