Java Agent-dynamic code modification

Source: Internet
Author: User

Java Agent-dynamic code modification

After an afternoon, I finally ran the java agent. This article records the specific operation steps to avoid forgetting...

You can use java agent to dynamically modify code (replace and modify class definitions) for AOP.

Objectives:

Implement the default ToString method for all classes added with the @ toString Annotation

Two programs are required, one for testing and the other for modifying the code. 1. Test Procedure

The tested programs include:

-ToString. java

-Foo. java

-Main. java

The Code is as follows:

ToString. java: Define the ToString Annotation

package com.chosen0ne.agent.test;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME)public @interface ToString {}

Foo. java: It is very simple for testing and uses the ToString annotation.

 

 

package com.chosen0ne.agent.test;@ToStringpublic class Foo {}

Main. java:
package com.chosen0ne.agent.test;public class Main {    public static void main(String[] args) {        Foo foo = new Foo();        System.out.println(foo.toString());    }}

Run Main. java and the result is as follows:
[email protected]
ToString returns the default Implementation of the Object. 2. Agent Program

Java agent programs are similar to hooks in two ways:

-Before the main function starts

-Running

Here we mainly test the situation before the main function starts. Similar to the main function

public static void premain(String agentArgs, Instrumentation inst);
This function will be called before the main function. You can perform Bytecode operations in premain to replace or re-implement some classes. Byte Buddy library is used here, which provides more advanced abstraction on ASM for ease of use. The Code is as follows:
package com.chosen0ne.ByteCode.agent;import java.lang.instrument.Instrumentation;import com.chosen0ne.agent.test.ToString;import net.bytebuddy.agent.builder.AgentBuilder;import net.bytebuddy.description.type.TypeDescription;import net.bytebuddy.dynamic.DynamicType.Builder;import net.bytebuddy.implementation.FixedValue;import net.bytebuddy.matcher.ElementMatchers;public class ToStringAgent {    public static void premain(String args, Instrumentation instrumentation) {        System.out.println("print pre main");        new AgentBuilder.Default()                .type(ElementMatchers.isAnnotatedWith(ToString.class))                .transform(new AgentBuilder.Transformer() {                    @Override                    public Builder
  transform(Builder
  builder,                            TypeDescription typeDescription, ClassLoader classLoader) {                        return builder.method(ElementMatchers.named("toString"))                                .intercept(FixedValue.value("test"));                    }                                    }).installOn(instrumentation);    }}
The agent needs to be packaged as a jar, and premain-Class must be specified in MANIFEST. MF for the Premain method to specify the Class containing the premain function. There are two methods for packaging:

1) run the jar command directly.

After editing and generating MANIFEST. MF, run:

jar cvfm agent.jar MANIFEST.MF -C . com lib
The jar package in the preceding command contains:

-Com: compiled class files

-Lib: the dependent Library

2) generate directly using maven:

Use the maven-jar-plugin plug-in to generate a jar package. The configuration is as follows:

<build>    <plugins>            <plugin>            <groupid>org.apache.maven.plugins</groupid>            <artifactid>maven-jar-plugin</artifactid>            <version>2.1</version>            <configuration>                <archive>                    <manifest>                        <addclasspath>true</addclasspath>                        <classpathprefix>lib/</classpathprefix>                        <mainclass>com.chosen0ne.ByteCode.ByteBuddyTest</mainclass>                    </manifest>                    <manifestentries>                        <premain-class>com.chosen0ne.ByteCode.agent.ToStringAgent</premain-class>                    </manifestentries>                </archive>            </configuration>        </plugin>    </plugins></build>
Auto properties are generated mainly through the manifestEntries tag, where the Premain-Class3 is specified. Run

Put the generated agent. jar, ByteBuddy jar package, and the class file compiled by the test program in a path. The directory layout is as follows:

.├── agent.jar├── classes│ └── com│     └── chosen0ne│         └── agent│             └── test│                 ├── Foo.class│                 ├── Main.class│                 └── ToString.class└── lib    └── byte-buddy-1.2.3.jar

Run the following command in the current directory:
java -cp classes:lib/byte-buddy-1.2.3.jar -javaagent:agent.jar com.chosen0ne.agent.test.Main
The running result is as follows:
print pre maintest

Note that if you package the test program into a jar package, you will fail to specify the ByteBuddy library through-cp. The corresponding class cannot be found. The error is as follows:
> java -cp classes:lib/byte-buddy-1.2.3.jar -javaagent:agent.jar -jar agent-test-case-0.0.1-SNAPSHOT.jarException in thread "main" java.lang.NoClassDefFoundError: net/bytebuddy/matcher/ElementMatcherat java.lang.Class.getDeclaredMethods0(Native Method)at java.lang.Class.privateGetDeclaredMethods(Class.java:2688)at java.lang.Class.getDeclaredMethod(Class.java:2115)at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:327)at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)Caused by: java.lang.ClassNotFoundException: net.bytebuddy.matcher.ElementMatcherat java.net.URLClassLoader$1.run(URLClassLoader.java:372)at java.net.URLClassLoader$1.run(URLClassLoader.java:361)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:360)at java.lang.ClassLoader.loadClass(ClassLoader.java:424)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)at java.lang.ClassLoader.loadClass(ClassLoader.java:357)... 5 moreFATAL ERROR in native method: processing of -javaagent failed
I do not know the specific reason... So you can run it directly in class.

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.