Java call key chain tracking technology (two) Javaagent

A, Javaagent

Many online About Javaagent, please find the degree of your mother and brother valley. The only mention is relatively easy to use bytecode is bytebuddy, a high degree of encapsulation, easy to use.

Second, the code sample

The following is the key code sample, the sample can be drawn according to scoop self-transformation.
1. Preparation of agent entry

package com.javashizhan.trace;

import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.isSetter;
import static net.bytebuddy.matcher.ElementMatchers.nameContainsIgnoreCase;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWithIgnoreCase;
import static net.bytebuddy.matcher.ElementMatchers.not;

import java.lang.instrument.Instrumentation;

import com.javashizhan.trace.interceptor.AbstractJunction;
import com.javashizhan.trace.interceptor.ProtectiveShieldMatcher;
import com.javashizhan.trace.interceptor.TraceInterceptor;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.NamedElement;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;

public class TraceAgent {
	
	public static void premain(String arguments, Instrumentation instrumentation) { 
		new AgentBuilder.Default()
		.type(buildMatch())
		.transform((builder, type, classLoader, module) ->
		builder.method(ElementMatchers.any())
						.intercept(MethodDelegation.to(TraceInterceptor.class)) // 拦截器
		).installOn(instrumentation);
	}
	
	public static ElementMatcher<? super TypeDescription> buildMatch() {
		ElementMatcher.Junction judge = new AbstractJunction<NamedElement>() {
            @Override
            public boolean matches(NamedElement target) {
                return true;
            }
        };
        judge = judge.and(not(isInterface())).and(not(isSetter()))
        		.and(nameStartsWithIgnoreCase("io.spring"))
				.and(not(nameContainsIgnoreCase("util")))
        		.and(not(nameContainsIgnoreCase("interceptor")));
        judge = judge.and(not(isSetter()));
        return new ProtectiveShieldMatcher(judge);
	}

}
复制代码

2. interceptor class TraceInterceptor.java

package com.javashizhan.trace.interceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;

import com.javashizhan.trace.domain.CallMethod;
import com.javashizhan.trace.TraceWrapper;
import com.javashizhan.trace.collector.DBCollector;
import com.javashizhan.trace.domain.Trace;
import com.javashizhan.trace.domain.TraceRecord;

import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

public class TraceInterceptor {
	
	@RuntimeType
    public static Object intercept(@Origin Method method,
        @SuperCall Callable<?> callable) throws Exception {
		
		before(method);
		
        try {
            return callable.call();
        } finally {
            after();
        }
    }
	
	public static void after() {
		Trace trace = TraceWrapper.getTrace(); //Trace类,可自行实现,不是关键
		
		if (null != trace) {
			if (trace.callMethodSize() > 0) {
				
				CallMethod callMethod = trace.pop();
				
				if (null != callMethod && callMethod.isTraceFlag()) {
					
					callMethod.calculateCostTime();
					trace.addTraceRecord(new TraceRecord(callMethod));
					
				}
				
				if (trace.callMethodSize() == 0) {
					List<TraceRecord> traceRecordList = trace.getAllTraceRecord();
					if (null != traceRecordList && traceRecordList.size() > 0) {
						DBCollector collector = new DBCollector(traceRecordList);
						new Thread(collector).start();
						TraceWrapper.destory();
					}
				}
			}
		}
	}
	
	private static void before(Method method) {
		Trace trace = TraceWrapper.getTrace();
		
		CallMethod callMethod = new CallMethod(method);
		if (isInnerClass(callMethod)) {    //spring中有很多内部类,可以去掉
			callMethod.setTraceFlag(false);
		} else {
			callMethod.setTraceFlag(true);
		}
		
		//不管是否跟踪都放进去
		trace.push(callMethod);
	}
	
	private static boolean isInnerClass(CallMethod callMethod) {
		 return callMethod.getClassName().indexOf('$') > -1;
	}
	
	
}
复制代码

3.AbstractJunction.java

package com.javashizhan.trace.interceptor;

import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatcher.Junction;
import net.bytebuddy.matcher.ElementMatcher.Junction.Conjunction;
import net.bytebuddy.matcher.ElementMatcher.Junction.Disjunction;

public abstract class AbstractJunction<V> implements ElementMatcher.Junction<V> {
    @Override
    public <U extends V> Junction<U> and(ElementMatcher<? super U> other) {
        return new Conjunction<U>(this, other);
    }

    @Override
    public <U extends V> Junction<U> or(ElementMatcher<? super U> other) {
        return new Disjunction<U>(this, other);
    }
}
复制代码

4.ProtectiveShieldMatcher.java

package com.javashizhan.trace.interceptor;

import net.bytebuddy.matcher.ElementMatcher;

public class ProtectiveShieldMatcher<T> extends ElementMatcher.Junction.AbstractBase<T> {

    private final ElementMatcher<? super T> matcher;

    public ProtectiveShieldMatcher(ElementMatcher<? super T> matcher) {
        this.matcher = matcher;
    }

    public boolean matches(T target) {
        try {
            return this.matcher.matches(target);
        } catch (Throwable t) {
            //logger.warn(t, "Byte-buddy occurs exception when match type.");
            return false;
        }
    }
}
复制代码

Two, pom file

<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>trace</groupId>
  <artifactId>chain</artifactId>
  <version>0.0.1-SNAPSHOT</version>
	
  <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <java.version>1.8</java.version>
		<!-- <spring-cloud.version>Finchley.SR1</spring-cloud.version>  -->
    </properties>

    <dependencies>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy</artifactId>
            <version>1.9.6</version>
        </dependency>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy-agent</artifactId>
            <version>1.9.6</version>
        </dependency>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>2.7.9</version>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.16</version>
        </dependency>
		
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                  implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <manifestEntries>
                                        <!--  <Premain-Class>com.undergrowth.secure.SecurityAgent</Premain-Class> -->
                                       <!-- <Premain-Class>com.undergrowth.agent.AgentToString</Premain-Class>-->
                                        <Premain-Class>com.javashizhan.trace.TraceAgent</Premain-Class>
                                    </manifestEntries>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
复制代码

Third, add startup parameters in Java applications

1. First agent project labeled jar package
2. Add the following VM startup parameters to be used in the agent's Java applications

-javaagent:D:\MyApp\apache-skywalking-apm-bin\agent\chain-0.0.1-SNAPSHOT.jar
复制代码

Note Replace jar package their own path.

end.


Micro-channel public number:


Adding "Java stack combat battalion" knowledge planet, participate in discussions, share the code more real!

t.zsxq.com/RNzfi2j

Guess you like

Origin juejin.im/post/5d48584af265da03c34be28e