Javassist bytecode Enhancement

Source: Internet
Author: User
Javassist is a strong and powerful driver for executing Bytecode operations. Code Library. It allows developers to add new methods to a compiled class or modify existing methods freely. However, unlike other similar libraries, Javassist does not require developers to have a deep understanding of bytecode. Similarly, it also allows developers to ignore the details and structure of the modified class.
The Code driver is usually used to modify compiled classes, or Program Automatic Creation of execution class and other related operations. This requires the bytecode engine to be able to modify programs at runtime or during compilation. Currently, some technologies use bytecode to enhance existing Java classes, and others use it or generate classes dynamically created by the system at runtime. For example, the jdo1.0 specification uses the bytecode technology to process and pre-compile tables in the database and then package them into Java classes. Especially in the Development of object-oriented systems, many framework systems use bytecode, so that we can better obtain the norm and dynamic nature of the program. Some EJB containers, such as the JBoss project, are dynamically created and loaded in the running state, which dramatically shortens
The period during which the EJB is deployed. This technology is so fascinating that standard Java. Lang. Reflect. proxy classes are also available in JDK to execute related operations.

However, writing bytecode is a very undesirable task for framework developers. To some extent, learning and using bytecode is like using an assembly language. This makes for most developers that, despite the considerable benefits of the program, the difficulty needed to climb it is sufficient to cool this enthusiasm. Furthermore, the use of bytecode in a program greatly reduces the readability and maintainability of the program.

This is a good buttered bread, but we can only drool through the window. Is that all we can do?

Fortunately, we still have Javassist. Javassist is a function library that can perform Bytecode operations. However, it is easy to understand. He allows developers to freely execute bytecode layer operations on their own programs. Of course, you do not need to have a deep understanding of bytecode, or you do not need to understand it at all.

API parallel to the reflection API

The outermost API of Javassist is similar to the API in the Java reflection package. It allows you to conveniently view the class structure before loading the classloder. It mainly consists of ctclass, ctmethod, and ctfield classes. It is used to perform the same operations as Java. Lang. Class, java. Lang. Reflect. method, and Java. Lang. Reflect. method. Field in the JDK reflection API. These classes allow you to easily obtain its structure, functions, and attributes before the target class is loaded. In addition, not only in terms of functions, but even in terms of structure, the execution Letter of these classes
The number is also roughly the same as that of the reflected API. For example, getname, getsuperclass, getmethods, getsignature, and so on. If you have some knowledge about the reflection mechanism of Java, it will be easy and happy to use the Javassist layer.

Next, we will provide an example of using Javassist to read information about org. Geometry. Point. Class (of course, do not forget to introduce the Javassist. * package ):

1. classpool pool = classpool. getdefault ();

2. ctclass Pt = pool. Get ("org. Geometry. Point ");

3. system. Out. println (Pt. getsuperclass (). getname ());

Classpool is the creation factory of ctclas. It finds the location of the ctclass in classpath and creates a ctclass instance for each analysis request. "Getsuperclass (). getname ()" shows the name of the parent class inherited by org. Geometry. Point. Class.

However, unlike the reflection API, Javassist does not provide the construction capability. In other words, we cannot obtain an instance of the org. Geometry. Point. Class class. On the other hand, before the class is instantiated, Javassist does not provide the calling interface for the function of the target class and the method for obtaining the attribute value. In the analysis phase, it only provides modifications to the class definition of the target class, but this is not what reflection APIs can do.

Example:

4. Pt. setsuperclass (pool. Get ("figure "));

In this way, the relationship between the target class and its parent class will be modified. We will change org. Geometry. Point. CLAS to inherit from the figure class. Of course, in terms of consistency, the compatibility between the figure class and the original parent class must be ensured.

Adding a new method to the target class is simpler. First, let's look at how bytecode is formed:

5. ctmethod M = ctnewmethod. Make ("Public int xmove (INT dx) {x + = DX;}", pt );

6. Pt. addmethod (m );

For the ctmethod class, we only need to write a small function to add a method. This is a big piece of good news. Developers no longer need to write a large series of VM commands to achieve such a small operation. Javassist will use a built-in compiler to help us complete this.

Finally, do not forget to instruct Javassist to store the written bytecode into your target class:

7. Pt. writefile ();

The writefile method can help us write the modified definition to the. Class file of the target class. Of course, we can even accomplish this when the target class is loaded. Javassist can work well with classloader and we will see this soon.

Javassist is not the first function library to complete the translation from code to bytecode. Jakarta's bcel is also a well-known bytecode engine tool. However, you cannot use bcel to complete code-level CAPTCHA operations. If you need to add a new method to a compiled class, if you use bcel, you can only define a sequence of commands consisting of a large string of bytecode. As mentioned above, this is not what we want to see. Therefore, in this regard, the use of code to insert new methods is truly a blessing.

Instrumenting a method body

Like the addition of methods, other operations on a class method are also defined at the code layer. In other words, although these steps are necessary, developers also do not need to directly operate and modify the VM's command sequence, which will be automatically completed by SIS. Of course, if developers think they need to manage and monitor these steps, or want to manage these operations by themselves, Javassist also provides a more underlying API for implementation, but here we areArticleWe will not discuss this topic further. Well, although in terms of structure, it is similar to bcel's bytecode layer API.

The idea of designing the operation API of Javassist on the subfunction body of the target class is based on the idea of Aspect-oriented programming (AOP. Javassist allows a statement with coupling relationships as a whole. It allows calling or obtaining other functions or attribute values in an insert statement. It automatically breaks down the priority of these statements and performs nested operations.

As shown in the following example, listing 1 includes a ctmethod, which mainly targets the draw method of the screen class. Then, we define a point class, which has a move operation to move the point. Of course, before moving, we hope to get the current position of the point through the draw method. Then, we need to add the following definition to the move method:

{System. Out. println ("move"); $ _ = $ proceed ($ );}

In this way, we can print its position before executing move. Note that the calling statement is in the following format:

$ _ = $ Proceed ($ );

In this way, process () in the original ctmethod class will be used to track the location of the point.

Based on the above situation, the methord operations of ctmethod are actually divided into the following steps. First, the methord of ctmethod will scan the insert Statement (CODE) itself. Once a sub-function is found, an expreditor instance is created to analyze and execute the sub-function operations. This operation will be completed before the entire insert statement is executed. If this instance has a static attribute, methord will first detect the insert statement. Then, before executing the insert to the target class --- Point class in the above example ---, the static property will automatically replace all the relevant parts in the insert Statement (CODE. However, it is worth noting that the above replacement operation will be performed after Javassist converts the insert Statement (CODE) into bytecode.
Complete.

Special Variables

In the replaced Statement (CODE), we may also need to use some special variables to call a subfunction. In this case, we need to use the keyword "$. In Javassist, "$" is used to declare a word thereafter as a special parameter, while "$ _" is used to declare a word thereafter as the return value of the function. When a special parameter is called, it should look like "$1, $2, $3". However, in particular, when the target class is called, is expressed as "$0 ". This format makes it much easier for developers to enter parameters for using subfunctions. For example:

{System. Out. println ("move"); $ _ = $ proceed ($1, 0 );}

Note that the first parameter of this subfunction is 0.

Another special type is $ Arg, which is actually an object queue that contains all the call parameters of the function. When the Javassist scans the $ Arg, if a parameter is of the Basic Java type, it automatically wraps the parameter and puts it into the queue. For example, if a parameter is of the int type, it will use the java. Lang. Integer class to wrap the int parameter and store it in the parameter queue. Compared with the Java reflection package: the invoke method in the Java. Lang. Reflect. methord class, $ ARGs is much easier.

Javassist also allows developers to insert certain statements (CODE) to the header of a function or the end of a function ). For example, it has an insertbefore method used to execute an operation before a function is called. Its usage is roughly like this:

1. classpool pool = classpool. getdefault ();
2. ctclass cc = pool. Get ("screen ");
3. ctmethod CM = cc. getdeclaredmethod ("Draw", new ctclass [0]);
4. cm. insertbefore ("{system. Out. println ($1); system. Out. println ($2 );}");
5. CC. writefile ();

The above example allows us to execute the print operation before calling the draw function-print out the two parameters passed to the draw.

Similarly, you can use the keyword $ to modify or wrap a function.

1. ctclass cc = sloader. Get ("point ");
2. ctmethod M1 = cc. getdeclaredmethod ("move ");
3. ctmethod m2 = ctnewmethod. Copy (M1, CC, null );
4. m1.setname (m1.getname () + "_ orig ");
5. m2.setbody ("{system. Out. println (" call "); return $ proceed ($ );
} "," This ", m1.getname ());
6. CC. addmethod (m2 );
7. CC. writefile ();

The first four lines of the above Code are not difficult to understand. Javassist first copies the move method in the point and creates a new function. Then, it renames the original move method that exists with the point class to "_ orig ". Next, let's take a look at the parameters in the fifth line of the program: the first parameter indicates that the function needs to print a piece of information in the initial part of execution, and then execute the subfunction proceed () and return results. This is similar to the move method and is easy to understand. The second parameter only declares the position of the class where the sub-function is located. This is the point class. The third parameter, "m1.getname ()", defines the name of the new function.

Javassist also has other operations and classes to help you implement functions such as modifying the value of a certain attribute, changing the return value of a function, and completing other operations after a function is executed. You can browse www.sist.org for related information.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.