diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..fcd44be
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+.idea
+*.iml
+*.ipr
+*.iws
+*/*.iml
+*/logs
+~
+~/*
+infer-out
+out
+.DS_Store
+*.classpath
+*.project
+*/*.classpath
+*/*.project
+*/*/*.project
+*/*/*.classpath
+*/*/*.iml
+*/.settings
+*/*/.settings
+logs
+csv-log/target
+csv-log/src/test
+csv-log/dependency-reduced-pom.xml
+dependency-reduced-pom.xml
+.idea/*
+target
+src/test
+*.csv
+/csv-log-save/shell/Untitled 3.py
+/csv-log-save/shell/ceate_offline_table.sh
+version.yml
diff --git a/README.md b/README.md
index 8b840dd..9d33ddc 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,3 @@
# byte-buddy-agent-example
+简单的使用byte-buddy来做成javaagent, 来修改springboot启动的任务
+里面修改了httpclient和redis的调用方法
diff --git a/agent/pom.xml b/agent/pom.xml
new file mode 100644
index 0000000..395a851
--- /dev/null
+++ b/agent/pom.xml
@@ -0,0 +1,98 @@
+
+
+ 4.0.0
+
+
+ com.dragon.study.bytebuddy
+ agent-example
+ 1.0.0-SNAPSHOT
+
+
+ agent
+ 1.0.0-SNAPSHOT
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 2.5.5
+
+
+ jar-with-dependencies
+
+
+ true
+
+ true
+ true
+
+
+ com.dragon.study.bytebuddy.MyAgent
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.8
+ 128m
+ 512m
+ true
+
+
+
+
+
+
+
+ net.bytebuddy
+ byte-buddy
+ 1.3.5
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+ 1.3.0.RELEASE
+ provided
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.3.2
+ provided
+
+
+
+ redis.clients
+ jedis
+ 2.8.0
+ provided
+
+
+
+ com.dragon.study.bytebuddy
+ app
+ 1.0.0-SNAPSHOT
+ provided
+
+
+
+
+
diff --git a/agent/src/main/java/com/dragon/study/bytebuddy/MyAgent.java b/agent/src/main/java/com/dragon/study/bytebuddy/MyAgent.java
new file mode 100644
index 0000000..6fbf93e
--- /dev/null
+++ b/agent/src/main/java/com/dragon/study/bytebuddy/MyAgent.java
@@ -0,0 +1,37 @@
+package com.dragon.study.bytebuddy;
+
+import com.dragon.study.bytebuddy.httpclient.HttpClientTransformer;
+import com.dragon.study.bytebuddy.redis.RedisTransformer;
+
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.dynamic.ClassFileLocator;
+import net.bytebuddy.pool.TypePool;
+
+import java.lang.instrument.Instrumentation;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+/**
+ * Created by dragon on 16/3/29.
+ */
+public class MyAgent {
+
+ public static void premain(String arg, Instrumentation instrumentation) {
+
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ ClassFileLocator.Compound compound = new ClassFileLocator.Compound(ClassFileLocator.ForClassLoader.of(classLoader), ClassFileLocator.ForClassLoader.ofClassPath());
+
+ String httpInterceptor = "com.dragon.study.bytebuddy.httpclient.HttpClientInterceptor";
+ String redisInterceptor = "com.dragon.study.bytebuddy.redis.RedisInterceptor";
+
+ new AgentBuilder.Default()
+ .type(named("org.apache.http.impl.client.CloseableHttpClient"))
+ .transform(new HttpClientTransformer(TypePool.Default.of(compound).describe(httpInterceptor).resolve()))
+ .type(named("redis.clients.jedis.Client"))
+ .transform(new RedisTransformer(TypePool.Default.of(compound).describe(redisInterceptor).resolve()))
+ .installOn(instrumentation);
+
+
+ }
+}
diff --git a/agent/src/main/java/com/dragon/study/bytebuddy/Trace.java b/agent/src/main/java/com/dragon/study/bytebuddy/Trace.java
new file mode 100644
index 0000000..fcafbc4
--- /dev/null
+++ b/agent/src/main/java/com/dragon/study/bytebuddy/Trace.java
@@ -0,0 +1,67 @@
+package com.dragon.study.bytebuddy;
+
+/**
+ * Created by dragon on 16/3/28.
+ */
+public class Trace {
+ private String url;
+ private int statusCode;
+ private long cost;
+ private Exception e;
+
+ public Trace() {
+ }
+
+ public Trace(String url, int statusCode, long cost, Exception e) {
+ this.url = url;
+ this.statusCode = statusCode;
+ this.cost = cost;
+ this.e = e;
+ }
+
+ public Trace(String url, int statusCode, long cost) {
+ this(url, statusCode, cost, null);
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusCode(int statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ public long getCost() {
+ return cost;
+ }
+
+ public void setCost(long cost) {
+ this.cost = cost;
+ }
+
+ public Exception getE() {
+ return e;
+ }
+
+ public void setE(Exception e) {
+ this.e = e;
+ }
+
+ @Override
+ public String toString() {
+ return "Trace{" +
+ "url='" + url + '\'' +
+ ", statusCode=" + statusCode +
+ ", cost=" + cost +
+ ", e=" + e +
+ '}';
+ }
+}
diff --git a/agent/src/main/java/com/dragon/study/bytebuddy/context/ApplicationContextHolder.java b/agent/src/main/java/com/dragon/study/bytebuddy/context/ApplicationContextHolder.java
new file mode 100644
index 0000000..99e8b34
--- /dev/null
+++ b/agent/src/main/java/com/dragon/study/bytebuddy/context/ApplicationContextHolder.java
@@ -0,0 +1,86 @@
+package com.dragon.study.bytebuddy.context;
+
+
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by Reilost on 14-3-4.
+ */
+public class ApplicationContextHolder implements ApplicationContextAware {
+ private static ApplicationContext _context;
+
+ private static Map mockBeans;
+
+ public static ApplicationContext getApplicatioinContext() {
+ return _context;
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext context) {
+ _context = context;
+ }
+
+ /**
+ * 将该对象中的带有Autowired annotation的属性自动注入
+ */
+ public static void autowireBean(Object obj) {
+ if (_context != null) {
+ AutowireCapableBeanFactory factory = _context.getAutowireCapableBeanFactory();
+ factory.autowireBean(obj);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T getBean(String name) {
+ return (T) _context.getBean(name);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T getBean(Class clazz) {
+ T bean = null;
+ if (mockBeans != null) {
+ bean = (T) mockBeans.get(clazz);
+ }
+ if (bean != null) {
+ return bean;
+ }
+
+
+ String[] names = _context.getBeanNamesForType(clazz);
+ if (names == null || names.length == 0) {
+ return null;
+ }
+ return (T) _context.getBean(names[0]);
+ }
+
+ public static List getBeans(Class clazz) {
+ List ret = new ArrayList();
+ if (_context == null) {
+ return ret;
+ }
+ String[] names = _context.getBeanNamesForType(clazz);
+ if (names == null || names.length == 0) {
+ return ret;
+ }
+ for (String name : names) {
+ ret.add((T) _context.getBean(name));
+ }
+ return ret;
+ }
+
+ public static void setMockBean(Class clazz, Object object) {
+ if (mockBeans == null) {
+ mockBeans = new HashMap();
+ }
+ mockBeans.put(clazz, object);
+ }
+
+
+}
diff --git a/agent/src/main/java/com/dragon/study/bytebuddy/httpclient/HttpClientInterceptor.java b/agent/src/main/java/com/dragon/study/bytebuddy/httpclient/HttpClientInterceptor.java
new file mode 100644
index 0000000..13a2aba
--- /dev/null
+++ b/agent/src/main/java/com/dragon/study/bytebuddy/httpclient/HttpClientInterceptor.java
@@ -0,0 +1,76 @@
+package com.dragon.study.bytebuddy.httpclient;
+
+import com.dragon.study.bytebuddy.Trace;
+import com.dragon.study.bytebuddy.bean.Person;
+import com.dragon.study.bytebuddy.context.ApplicationContextHolder;
+
+import net.bytebuddy.implementation.bind.annotation.AllArguments;
+import net.bytebuddy.implementation.bind.annotation.SuperCall;
+
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.RequestLine;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Created by dragon on 16/3/29.
+ */
+public class HttpClientInterceptor {
+
+ public static CloseableHttpResponse doExecute(
+ @SuperCall
+ Callable client,
+ @AllArguments
+ Object[] args) throws Exception {
+ Person person = ApplicationContextHolder.getBean(Person.class);
+ Trace trace = new Trace();
+ long start = System.currentTimeMillis();
+ try {
+ trace.setUrl(extractRequestUrl(args));
+ CloseableHttpResponse response = client.call();
+ trace.setCost(System.currentTimeMillis() - start);
+ trace.setStatusCode(response.getStatusLine().getStatusCode());
+ System.out.println("trace is " + trace + ", person is " + person.toString());
+ return response;
+ } catch (Exception e) {
+ trace.setCost(System.currentTimeMillis() - start);
+ trace.setE(e);
+ trace.setStatusCode(-1);
+ System.out.println("exception trace is " + trace + ", person is " + person.toString());
+ throw e;
+ }
+ }
+
+ private static String extractRequestUrl(Object[] args) {
+ if (args[0] instanceof HttpHost) {
+ HttpHost host = (HttpHost) args[0];
+ HttpRequest request = (HttpRequest) args[1];
+ return getRequestUrl(host, request);
+ } else if (args[0] instanceof HttpUriRequest) {
+ HttpUriRequest request = (HttpUriRequest) args[0];
+ if (request != null && request.getURI() != null) {
+ StringBuilder builder = new StringBuilder(1024);
+ builder.append(request.getMethod()).append(" ").append(request.getURI().toString());
+ return builder.toString();
+ } else {
+ return "";
+ }
+ } else {
+ return "";
+ }
+ }
+
+ private static String getRequestUrl(HttpHost host, HttpRequest request) {
+ StringBuilder builder = new StringBuilder(1024);
+ if (request != null && request.getRequestLine() != null && host != null) {
+ RequestLine requestLine = request.getRequestLine();
+ builder.append(requestLine.getMethod()).append(" ").append(host.toURI())
+ .append(requestLine.getUri());
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/agent/src/main/java/com/dragon/study/bytebuddy/httpclient/HttpClientTransformer.java b/agent/src/main/java/com/dragon/study/bytebuddy/httpclient/HttpClientTransformer.java
new file mode 100644
index 0000000..c7b1a0d
--- /dev/null
+++ b/agent/src/main/java/com/dragon/study/bytebuddy/httpclient/HttpClientTransformer.java
@@ -0,0 +1,34 @@
+package com.dragon.study.bytebuddy.httpclient;
+
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.dynamic.DynamicType;
+import net.bytebuddy.implementation.MethodDelegation;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.returns;
+
+/**
+ * Created by dragon on 16/3/29.
+ */
+public class HttpClientTransformer implements AgentBuilder.Transformer {
+
+ private final TypeDescription delegator;
+
+ public HttpClientTransformer(TypeDescription delegator) {
+ this.delegator = delegator;
+ }
+
+ @Override
+ public DynamicType.Builder transform(DynamicType.Builder> builder,
+ TypeDescription typeDescription, ClassLoader classLoader) {
+ try {
+ return builder.method(named("execute")
+ .and(returns(named("org.apache.http.client.methods.CloseableHttpResponse"))))
+ .intercept(MethodDelegation.to(delegator));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return builder;
+ }
+ }
+}
diff --git a/agent/src/main/java/com/dragon/study/bytebuddy/redis/RedisInterceptor.java b/agent/src/main/java/com/dragon/study/bytebuddy/redis/RedisInterceptor.java
new file mode 100644
index 0000000..00a7be6
--- /dev/null
+++ b/agent/src/main/java/com/dragon/study/bytebuddy/redis/RedisInterceptor.java
@@ -0,0 +1,49 @@
+package com.dragon.study.bytebuddy.redis;
+
+import com.dragon.study.bytebuddy.Trace;
+import com.dragon.study.bytebuddy.bean.Person;
+import com.dragon.study.bytebuddy.context.ApplicationContextHolder;
+
+import net.bytebuddy.implementation.bind.annotation.AllArguments;
+import net.bytebuddy.implementation.bind.annotation.SuperCall;
+
+import java.util.concurrent.Callable;
+
+import redis.clients.jedis.Connection;
+
+/**
+ * Created by dragon on 16/3/29.
+ */
+public class RedisInterceptor {
+
+ public static Connection sendMessage(
+ @SuperCall
+ Callable client,
+ @AllArguments
+ Object[] args) throws Exception {
+
+ Person person = ApplicationContextHolder.getBean(Person.class);
+ Trace trace = new Trace();
+ long start = System.currentTimeMillis();
+
+ try {
+ int i = 0;
+ for(Object arg : args) {
+ System.out.println("redis arg index: " + i++ + ", value is " + arg.toString());
+ }
+
+ trace.setUrl("local redis");
+ Connection response = client.call();
+ trace.setCost(System.currentTimeMillis() - start);
+ trace.setStatusCode(200);
+ System.out.println("trace is " + trace + ", person is " + person.toString());
+ return response;
+ } catch (Exception e) {
+ trace.setCost(System.currentTimeMillis() - start);
+ trace.setE(e);
+ trace.setStatusCode(-1);
+ System.out.println("exception trace is " + trace + ", person is " + person.toString());
+ throw e;
+ }
+ }
+}
diff --git a/agent/src/main/java/com/dragon/study/bytebuddy/redis/RedisTransformer.java b/agent/src/main/java/com/dragon/study/bytebuddy/redis/RedisTransformer.java
new file mode 100644
index 0000000..2479d39
--- /dev/null
+++ b/agent/src/main/java/com/dragon/study/bytebuddy/redis/RedisTransformer.java
@@ -0,0 +1,34 @@
+package com.dragon.study.bytebuddy.redis;
+
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.dynamic.DynamicType;
+import net.bytebuddy.implementation.MethodDelegation;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.returns;
+
+/**
+ * Created by dragon on 16/3/29.
+ */
+public class RedisTransformer implements AgentBuilder.Transformer {
+
+ private final TypeDescription delegator;
+
+ public RedisTransformer(TypeDescription delegator) {
+ this.delegator = delegator;
+ }
+
+ @Override
+ public DynamicType.Builder transform(DynamicType.Builder> builder,
+ TypeDescription typeDescription, ClassLoader classLoader) {
+ try {
+ return builder.method(named("sendCommand")
+ .and(returns(named("redis.clients.jedis.Connection"))))
+ .intercept(MethodDelegation.to(delegator));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return builder;
+ }
+ }
+}
diff --git a/app/pom.xml b/app/pom.xml
new file mode 100644
index 0000000..9fa7503
--- /dev/null
+++ b/app/pom.xml
@@ -0,0 +1,54 @@
+
+
+
+ com.dragon.study.bytebuddy
+ agent-example
+ 1.0.0-SNAPSHOT
+
+
+ 4.0.0
+ 1.0.0-SNAPSHOT
+ app
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+ exec
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+ 1.3.0.RELEASE
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.3.2
+
+
+
+ redis.clients
+ jedis
+ 2.8.0
+
+
+
diff --git a/app/src/main/java/com/dragon/study/bytebuddy/Application.java b/app/src/main/java/com/dragon/study/bytebuddy/Application.java
new file mode 100644
index 0000000..3007c9a
--- /dev/null
+++ b/app/src/main/java/com/dragon/study/bytebuddy/Application.java
@@ -0,0 +1,19 @@
+package com.dragon.study.bytebuddy;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * Created by dragon on 16/3/29.
+ */
+@ComponentScan
+@EnableScheduling
+@EnableAutoConfiguration
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/app/src/main/java/com/dragon/study/bytebuddy/bean/Person.java b/app/src/main/java/com/dragon/study/bytebuddy/bean/Person.java
new file mode 100644
index 0000000..51a4f6c
--- /dev/null
+++ b/app/src/main/java/com/dragon/study/bytebuddy/bean/Person.java
@@ -0,0 +1,34 @@
+package com.dragon.study.bytebuddy.bean;
+
+/**
+ * Created by dragon on 16/3/28.
+ */
+public class Person {
+
+ private String name;
+ private int age;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ @Override
+ public String toString() {
+ return "Person{" +
+ "name='" + name + '\'' +
+ ", age=" + age +
+ '}';
+ }
+}
diff --git a/app/src/main/java/com/dragon/study/bytebuddy/config/PersonConfiguration.java b/app/src/main/java/com/dragon/study/bytebuddy/config/PersonConfiguration.java
new file mode 100644
index 0000000..8af3fa0
--- /dev/null
+++ b/app/src/main/java/com/dragon/study/bytebuddy/config/PersonConfiguration.java
@@ -0,0 +1,22 @@
+package com.dragon.study.bytebuddy.config;
+
+import com.dragon.study.bytebuddy.bean.Person;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Created by dragon on 16/3/28.
+ */
+@Configuration
+public class PersonConfiguration {
+
+ @Bean
+ public Person person() {
+ Person person = new Person();
+ person.setName("longzhe");
+ person.setAge(29);
+ return person;
+ }
+
+}
diff --git a/app/src/main/java/com/dragon/study/bytebuddy/timer/TimerPerson.java b/app/src/main/java/com/dragon/study/bytebuddy/timer/TimerPerson.java
new file mode 100644
index 0000000..1739805
--- /dev/null
+++ b/app/src/main/java/com/dragon/study/bytebuddy/timer/TimerPerson.java
@@ -0,0 +1,48 @@
+package com.dragon.study.bytebuddy.timer;
+
+import com.dragon.study.bytebuddy.bean.Person;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClients;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+import redis.clients.jedis.Jedis;
+
+/**
+ * Created by dragon on 16/3/28.
+ */
+@Component
+public class TimerPerson {
+
+ @Autowired
+ private Person person;
+
+ @Scheduled(fixedDelay = 5000L, initialDelay = 1000L)
+ public void httpClientTest() {
+ System.out.println(person.toString() + " calling http client, time is " + System.currentTimeMillis());
+ try {
+ CloseableHttpResponse response = HttpClients.createDefault()
+ .execute(new HttpGet("http://enjoy.ricebook.com/"));
+ System.out.println(response.getStatusLine());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @Scheduled(fixedDelay = 10000L, initialDelay = 3000L)
+ public void redisTest() {
+ System.out.println(person.toString() + " calling redis, time is " + System.currentTimeMillis());
+ Jedis jedis = new Jedis("127.0.0.1", 6379);
+ jedis.set("a", "b");
+ String value = jedis.get("a");
+ System.out.println("key is a, value is " + value);
+ jedis.close();
+
+ }
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..d50dbc5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,18 @@
+
+
+ 4.0.0
+
+ com.dragon.study.bytebuddy
+ agent-example
+ pom
+ 1.0.0-SNAPSHOT
+
+ agent
+ app
+
+
+
+
+
diff --git a/run.sh b/run.sh
new file mode 100644
index 0000000..d63d584
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,3 @@
+mvn clean package
+java -javaagent:./agent/target/agent-1.0.0-SNAPSHOT-jar-with-dependencies.jar -jar app/target/app-1.0.0-SNAPSHOT-exec.jar
+