diff --git a/skywalking-sdk-plugin/pom.xml b/skywalking-sdk-plugin/pom.xml
index 2cafbda58..e92dbf455 100644
--- a/skywalking-sdk-plugin/pom.xml
+++ b/skywalking-sdk-plugin/pom.xml
@@ -7,6 +7,7 @@
1.0-SNAPSHOT
../skywalking-api/skywalking-sdk-plugin
+ spring-plugin
pom
diff --git a/skywalking-sdk-plugin/spring-plugin/pom.xml b/skywalking-sdk-plugin/spring-plugin/pom.xml
index 32386e78a..ad274276c 100644
--- a/skywalking-sdk-plugin/spring-plugin/pom.xml
+++ b/skywalking-sdk-plugin/spring-plugin/pom.xml
@@ -1,6 +1,4 @@
-
-
skywalking-sdk-plugin
@@ -10,6 +8,55 @@
4.0.0
spring-plugin
+ jar
+ spring-plugin
+ http://maven.apache.org
-
\ No newline at end of file
+
+ UTF-8
+
+
+
+
+ junit
+ junit
+ 3.8.1
+ compile
+
+
+ org.springframework
+ spring-beans
+ 3.2.0.RELEASE
+ compile
+
+
+ org.springframework
+ spring-context
+ 3.2.0.RELEASE
+ test
+
+
+ org.springframework
+ spring-aop
+ 3.2.0.RELEASE
+ test
+
+
+ org.aspectj
+ aspectjweaver
+ 1.8.7
+ test
+
+
+ org.javassist
+ javassist
+ 3.20.0-GA
+
+
+ com.ai.cloud
+ skywalking-api
+ 1.0-SNAPSHOT
+
+
+
diff --git a/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/SpringBuriedPoint.java b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/SpringBuriedPoint.java
deleted file mode 100644
index 6cee452a8..000000000
--- a/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/SpringBuriedPoint.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.ai.cloud.skywalking.plugin.spring;
-
-/**
- * Created by astraea on 2015/11/9.
- */
-public class SpringBuriedPoint {
-}
diff --git a/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/Tracing.java b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/Tracing.java
new file mode 100644
index 000000000..30ce1217a
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/Tracing.java
@@ -0,0 +1,11 @@
+package com.ai.cloud.skywalking.plugin.spring;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Tracing {
+}
diff --git a/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingEnhanceProcessor.java b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingEnhanceProcessor.java
new file mode 100644
index 000000000..fcfe91376
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingEnhanceProcessor.java
@@ -0,0 +1,175 @@
+package com.ai.cloud.skywalking.plugin.spring;
+
+import com.ai.cloud.skywalking.buriedpoint.LocalBuriedPointSender;
+import com.ai.cloud.skywalking.model.SendData;
+import javassist.*;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class TracingEnhanceProcessor implements BeanPostProcessor {
+
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ List methods = new ArrayList();
+ for (Method method : bean.getClass().getMethods()) {
+ if (method.isAnnotationPresent(Tracing.class)) {
+ methods.add(method);
+ }
+ }
+ if (methods.size() > 0) {
+ try {
+ ClassPool mPool = new ClassPool(true);
+ //创建代理类
+ CtClass mCtc = createProxyClass(bean, mPool);
+ //代理类继承所有的被代理的接口
+ inheritanceAllInterfaces(bean, mPool, mCtc);
+ //
+ mCtc.setSuperclass(mPool.get(bean.getClass().getName()));
+ //添加字段
+ mCtc.addField(CtField.make("private " + LocalBuriedPointSender.class.getName() + " buriedPoint;", mCtc));
+ mCtc.addField(CtField.make("private " + bean.getClass().getName() + " realBean;", mCtc));
+ // 校验方法
+ for (Method method : methods) {
+ // 生成方法头
+ StringBuilder result = new StringBuilder();
+ result.append(generateMethodHead(method));
+ // 生成方法参数
+ result.append(generateMethodParameter(method));
+ // 生成抛出异常
+ result.append(generateException(method));
+ // 生成方法体
+ result.append(generateMethodBody(bean, method));
+ // TODO 注解
+ // TODO 参数注解
+ mCtc.addMethod(CtMethod.make(result.toString(), mCtc));
+ }
+ mCtc.addConstructor(CtNewConstructor.make("public " + bean.getClass().getSimpleName() + "Proxy(" + LocalBuriedPointSender.class
+ .getName() + " buriedPoint, " + bean.getClass().getName() + " realBean){" +
+ "this.buriedPoint = buriedPoint;this.realBean = realBean;}", mCtc));
+ mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));
+ Class classes = mCtc.toClass();
+ Constructor constructor = classes.getConstructor(LocalBuriedPointSender.class, bean.getClass());
+ return constructor.newInstance(new LocalBuriedPointSender(), bean);
+ } catch (CannotCompileException e) {
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (NotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return bean;
+ }
+
+ private String generateMethodBody(Object bean, Method method) {
+ StringBuilder result = new StringBuilder();
+ result.append("{");
+ result.append(" try{ this.buriedPoint.beforeSend");
+ result.append(generateBeforeSendParamter(bean, method));
+ if (!"void".equals(method.getReturnType().getSimpleName())) {
+ result.append(" return ");
+ }
+ result.append("this.realBean." + method.getName());
+ result.append(generateMethodInvokeParameters(method));
+ result.append("}catch(Throwable e){");
+ result.append(" this.buriedPoint.handleException(e);");
+ result.append(" throw e;");
+ result.append("}finally{");
+ result.append(generateAfterTracing());
+ result.append("}}");
+ return result.toString();
+ }
+
+ private String generateBeforeSendParamter(Object bean, Method method) {
+ StringBuilder builder = new StringBuilder("(" + SendData.class.getName() + ".newBuilder().viewPoint(\""
+ + bean.getClass().getName() + "." + method.getName());
+ builder.append("(");
+ for (Class param : method.getParameterTypes()) {
+ builder.append(param.getSimpleName() + ",");
+ }
+ if (method.getGenericParameterTypes().length > 0) {
+ builder = builder.delete(builder.length() - 1, builder.length());
+ }
+ builder.append(")");
+ builder.append("\").build());");
+ return builder.toString();
+ }
+
+ private String generateMethodInvokeParameters(Method method) {
+ StringBuilder result = new StringBuilder();
+ int index;
+ result.append("(");
+ index = 0;
+ for (Class parameter : method.getParameterTypes()) {
+ result.append(parameter.getSimpleName().toLowerCase() + "$" + (index++) + ",");
+ }
+ if (method.getParameterTypes().length > 0) {
+ result = result.delete(result.length() - 1, result.length());
+ }
+ result.append(");");
+ return result.toString();
+ }
+
+ private String generateAfterTracing() {
+ return " this.buriedPoint.afterSend();";
+ }
+
+ private String generateException(Method method) {
+ StringBuilder resultB = new StringBuilder(" throws ");
+ for (Class exceptionClasses : method.getExceptionTypes()) {
+ resultB.append(exceptionClasses.getName() + ",");
+ }
+ if (method.getExceptionTypes().length > 0) {
+ resultB.delete(resultB.length() - 1, resultB.length());
+ } else {
+ resultB = new StringBuilder();
+ }
+ return resultB.toString();
+ }
+
+ private String generateMethodParameter(Method method) {
+ StringBuilder result = new StringBuilder();
+ result.append("(");
+ int index = 0;
+ for (Class param : method.getParameterTypes()) {
+ result.append(param.getSimpleName() + " " + param.getSimpleName().
+ toLowerCase() + "$" + (index++) + ",");
+ }
+ if (method.getGenericParameterTypes().length > 0) {
+ result = result.delete(result.length() - 1, result.length());
+ }
+ result.append(")");
+ return result.toString();
+ }
+
+ private String generateMethodHead(Method method) {
+ return "public " + method.getReturnType().getSimpleName() + " " + method.getName();
+ }
+
+ private CtClass createProxyClass(Object bean, ClassPool mPool) {
+ return mPool.makeClass(bean.getClass().getSimpleName() + "Proxy$" + ThreadLocalRandom.current().nextInt(100));
+ }
+
+ private void inheritanceAllInterfaces(Object bean, ClassPool mPool, CtClass mCtc) throws NotFoundException {
+ for (Class classes : bean.getClass().getInterfaces()) {
+ mCtc.addInterface(mPool.get(classes.getClass().getName()));
+ }
+ }
+
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+}
\ No newline at end of file
diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/AspectBean.java b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/AspectBean.java
new file mode 100644
index 000000000..adf2ff3ce
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/AspectBean.java
@@ -0,0 +1,11 @@
+package com.ai.cloud.skywalking.plugin.spring.aspect;
+
+public class AspectBean {
+ public void before() {
+ System.out.println("before aspect");
+ }
+
+ public void after() {
+ System.out.println("after aspect");
+ }
+}
diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/TestAspect.java b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/TestAspect.java
new file mode 100644
index 000000000..9ba0f5a00
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/TestAspect.java
@@ -0,0 +1,13 @@
+package com.ai.cloud.skywalking.plugin.spring.aspect;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class TestAspect {
+
+ public static void main(String[] args) {
+ ClassPathXmlApplicationContext classPathXmlApplicationContext =
+ new ClassPathXmlApplicationContext("classpath*:springConfig-aspect.xml");
+ TracingAspectBean testBuriedPointBean = classPathXmlApplicationContext.getBean(TracingAspectBean.class);
+ testBuriedPointBean.doBusiness();
+ }
+}
diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/TracingAspectBean.java b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/TracingAspectBean.java
new file mode 100644
index 000000000..300f59e0b
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/aspect/TracingAspectBean.java
@@ -0,0 +1,12 @@
+package com.ai.cloud.skywalking.plugin.spring.aspect;
+
+import com.ai.cloud.skywalking.plugin.spring.Tracing;
+
+public class TracingAspectBean {
+
+ @Tracing
+ public String doBusiness() {
+ System.out.println("do business");
+ return "Hello World";
+ }
+}
diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/common/TestBuriedPoint.java b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/common/TestBuriedPoint.java
new file mode 100644
index 000000000..e26793737
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/common/TestBuriedPoint.java
@@ -0,0 +1,13 @@
+package com.ai.cloud.skywalking.plugin.spring.common;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class TestBuriedPoint {
+
+ public static void main(String[] args) {
+ ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath*:springConfig-common.xml");
+ TestBuriedPointBean testBuriedPointBean = classPathXmlApplicationContext.getBean(TestBuriedPointBean.class);
+ testBuriedPointBean.sayTest();
+ System.out.println(testBuriedPointBean.addStr(1));
+ }
+}
diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/common/TestBuriedPointBean.java b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/common/TestBuriedPointBean.java
new file mode 100644
index 000000000..65810c041
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/common/TestBuriedPointBean.java
@@ -0,0 +1,27 @@
+package com.ai.cloud.skywalking.plugin.spring.common;
+
+import com.ai.cloud.skywalking.plugin.spring.Tracing;
+
+
+public class TestBuriedPointBean {
+ @Tracing
+ public void sayTest() throws RuntimeException, IllegalStateException {
+ System.out.println("say Test");
+ }
+
+ @Tracing
+ public static void sayTest1() {
+ System.out.println("xx");
+ }
+
+ @Tracing
+ public String addStr(int a, String c) {
+ throw new RuntimeException("aa");
+ }
+
+ @Tracing
+ public String addStr(int a) {
+ throw new RuntimeException("aa");
+ }
+
+}
diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/resources/springConfig-aspect.xml b/skywalking-sdk-plugin/spring-plugin/src/test/resources/springConfig-aspect.xml
new file mode 100644
index 000000000..09ad933a0
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/test/resources/springConfig-aspect.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/resources/springConfig-common.xml b/skywalking-sdk-plugin/spring-plugin/src/test/resources/springConfig-common.xml
new file mode 100644
index 000000000..1b289fda9
--- /dev/null
+++ b/skywalking-sdk-plugin/spring-plugin/src/test/resources/springConfig-common.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file