java agent开发

作者: 我叫王也道长 | 来源:发表于2018-03-22 21:49 被阅读0次

    java agent介绍

    java agent是jvm插件或者叫做代理,她是运行在main方法之前,她内定的方法名称叫premain。

    java agent 概述

    https://ws1.sinaimg.cn/large/afc434bdly1fplw4dc0lzj20j70ch74u.jpg

    接下来我们进行开发

    1. 实现premain方法

      package org.xxz;
      
      public class AgentMain {
        public static void premain(String args, Instrumentation inst) {
          System.out.println('hello java agent');
        }
      }
      

      上面的这段代码就完成了java agent的第一步了

    2. 打包

      这里我们使用maven的方式进行打包,请看下面的配置文件

      <build>
               <finalName>java-agent</finalName>
              <plugins>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-compiler-plugin</artifactId>
                      <configuration>
                          <source>1.8</source>
                          <target>1.8</target>
                          <encoding>utf-8</encoding>
                      </configuration>
                  </plugin>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-assembly-plugin</artifactId>
                      <version>3.0.0</version>
                      <configuration>
                          <archive>
                              <manifest>
                                  <addClasspath>true</addClasspath>
                              </manifest>
                              <manifestEntries>
                                  <Premain-Class>org.xxz.AgentMain</Premain-Class>
                              </manifestEntries>
                          </archive>
                          <descriptorRefs>
                              <descriptorRef>jar-with-dependencies</descriptorRef>
                          </descriptorRefs>
                      </configuration>
                      <executions>
                          <execution>
                              <id>make-assembly</id>
                              <phase>package</phase>
                              <goals>
                                  <goal>single</goal>
                              </goals>
                          </execution>
                      </executions>
                  </plugin>
              </plugins>
          </build>
      
    3. 使用java agent

      新建一个maven工程,打包然后运行

      java -jar demo.jar -javaagent:/apps/java-agent.jar
      

      执行上面的运行命令后,在我们控制台输出时就会看到hello java agent的字样哦!!!

    看到这里就结束了吗?没有哦,我们来看一个小例子。。。。。。。

    新建maven工程

    java-agent
    --src
        --main
            --java
                --org.xxz
                    --AgentMain.java
                    --TimeInterceptor.java
                    --TraceTime.java
            --resource
        --test
    --pom.xml
    

    首先看看我们的pom.xml是如何配置的

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.xxz</groupId>
        <artifactId>java-agent</artifactId>
        <version>1.0</version>
    
        <properties>
            <bytebuddy.version>1.8.0</bytebuddy.version>
            <slf4j.version>1.7.25</slf4j.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>net.bytebuddy</groupId>
                <artifactId>byte-buddy</artifactId>
                <version>${bytebuddy.version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>utf-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>3.0.0</version>
                    <configuration>
                        <archive>
                            <manifest>
                                <addClasspath>true</addClasspath>
                            </manifest>
                            <manifestEntries>
                                <Premain-Class>org.xxz.AgentMain</Premain-Class>
                            </manifestEntries>
                        </archive>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    

    这里我们使用了bytebuddy,不懂得看官可以上官方网站瞧瞧http://bytebuddy.net/

    再来看看我们得AgentMain.java

    package org.xxz;
    
    import net.bytebuddy.agent.builder.AgentBuilder;
    import net.bytebuddy.description.method.MethodDescription;
    import net.bytebuddy.description.type.TypeDescription;
    import net.bytebuddy.dynamic.DynamicType;
    import net.bytebuddy.implementation.MethodDelegation;
    import net.bytebuddy.matcher.ElementMatchers;
    import net.bytebuddy.utility.JavaModule;
    
    import java.lang.instrument.Instrumentation;
    
    /**
     * @author tt
     */
    public class AgentMain {
    
        public static void premain(String args, Instrumentation inst) {
    
            AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
                @Override
                public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                                                        TypeDescription typeDescription,
                                                        ClassLoader classLoader,
                                                        JavaModule javaModule) {
                    return builder
                            .method(ElementMatchers.any()) // 拦截任意方法
                            .intercept(MethodDelegation.to(TimeInterceptor.class)); // 委托
                }
            };
    
            AgentBuilder.Listener listener = new AgentBuilder.Listener() {
                @Override
                public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {
    
                }
    
                @Override
                public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
    
                }
    
                @Override
                public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {
    
                }
    
                @Override
                public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {
    
                }
    
                @Override
                public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {
    
                }
            };
    
            new AgentBuilder
                    .Default()
                    .type(ElementMatchers.nameStartsWith("org.xxz"))// 指定需要拦截的类
                    .transform(transformer)
                    .with(listener)
                    .installOn(inst);
    
        }
    
    }
    

    这里我们看看我们得TimeInterceptor.java

    package org.xxz;
    
    import net.bytebuddy.implementation.bind.annotation.Origin;
    import net.bytebuddy.implementation.bind.annotation.RuntimeType;
    import net.bytebuddy.implementation.bind.annotation.SuperCall;
    
    import java.lang.reflect.Method;
    import java.util.concurrent.Callable;
    
    /**
     * @author tt
     */
    public class TimeInterceptor {
    
        @RuntimeType
        public static Object interceptor(@Origin Class clazz,
                                       @Origin Method method,
                                       @SuperCall Callable<?> callable) throws Exception {
    
            TraceTime traceTime = method.getAnnotation(TraceTime.class);
    
            if (traceTime == null) {
                return callable.call();
            }
    
            long start = System.currentTimeMillis();
            try {
                // 原有函数执行
                return callable.call();
            } finally {
                System.out.println(clazz.getSimpleName() + "#" + method.getName() + " cost " + (System.currentTimeMillis() - start) + "ms");
            }
        }
    
    }
    

    最后就是我们得注解了TraceTime.java

    package org.xxz;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author tt
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TraceTime {
    }
    
    

    到这里我们得java-agent就开发完成了。。。。。是不是很简单啊。。。。

    接下来,我们看看使用方式咯。。。。。

    java-agent-test
    --src
        --main
            --java
                --org.xxz
                    --test
                        --AgentMainTest.java
                        --Demo.java
                    --TraceTime.java
            --resource
        --test
    --pom.xml
    

    依旧先看我们得pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.xxz</groupId>
        <artifactId>java-agent-test</artifactId>
        <version>1.0</version>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>utf-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    这里的pom文件上面的简单多了。

    看看我们的测试类AgentMainTest.java

    package org.xxz.test;
    /**
     * @author tt
     */
    public class AgentMainTest {
    
        public static void main(String[] args) throws Exception {
            Demo demo = new Demo();
            demo.print("agent");
        }
    }
    

    看看我们的Demo.java

    package org.xxz.test;
    
    import org.xxz.TraceTime;
    
    /**
     * @author tt
     */
    public class Demo {
    
        @TraceTime
        public void print(String string) throws InterruptedException {
            Thread.sleep(100L);
            System.out.println("hello " + string);
        }
    }
    

    这里还少了一个TraceTime.java,把上面的拷贝过来哦。。。。注意包的结构要一样哦。。。。。

    上面介绍了如何命令行使用java-agent.jar,这里我们介绍如何再IDE中使用,要上图了哦。。。。。

    image

    好了,今天的文章到这里就结束了。。。

    最后还来一张运行结果吧。。。。

    image

    原文地址:https://blog.uyiplus.com/2018/java-agent-01/

    相关文章

      网友评论

        本文标题:java agent开发

        本文链接:https://www.haomeiwen.com/subject/komzqftx.html