增加Skywalking的Spring埋点和测试类

This commit is contained in:
zhangxin10 2015-11-10 15:17:12 +08:00
parent d089c475c9
commit 64d66eb3c2
12 changed files with 356 additions and 11 deletions

View File

@ -7,6 +7,7 @@
<version>1.0-SNAPSHOT</version>
<modules>
<module>../skywalking-api/skywalking-sdk-plugin</module>
<module>spring-plugin</module>
</modules>
<packaging>pom</packaging>

View File

@ -1,6 +1,4 @@
<?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"
<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">
<parent>
<artifactId>skywalking-sdk-plugin</artifactId>
@ -10,6 +8,55 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-plugin</artifactId>
<packaging>jar</packaging>
<name>spring-plugin</name>
<url>http://maven.apache.org</url>
</project>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
</dependency>
<dependency>
<groupId>com.ai.cloud</groupId>
<artifactId>skywalking-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -1,7 +0,0 @@
package com.ai.cloud.skywalking.plugin.spring;
/**
* Created by astraea on 2015/11/9.
*/
public class SpringBuriedPoint {
}

View File

@ -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 {
}

View File

@ -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<Method> methods = new ArrayList<Method>();
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;
}
}

View File

@ -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");
}
}

View File

@ -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();
}
}

View File

@ -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";
}
}

View File

@ -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));
}
}

View File

@ -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");
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="postProcess1"
class="com.ai.cloud.skywalking.plugin.spring.TracingEnhanceProcessor">
</bean>
<bean id="aspectBean" class="com.ai.cloud.skywalking.plugin.spring.aspect.AspectBean"/>
<bean id="testBuriedPointAspect" class="com.ai.cloud.skywalking.plugin.spring.aspect.TracingAspectBean"/>
<aop:config>
<aop:aspect ref="aspectBean">
<aop:pointcut id="testPointCut"
expression="execution(* com.ai.cloud.skywalking.plugin.spring.aspect..*(..))"/>
<aop:before method="before" pointcut-ref="testPointCut"/>
<aop:after method="after" pointcut-ref="testPointCut"/>
</aop:aspect>
</aop:config>
</beans>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="postProcess1"
class="com.ai.cloud.skywalking.plugin.spring.TracingEnhanceProcessor">
</bean>
<bean id="testBean" class="com.ai.cloud.skywalking.plugin.spring.common.TestBuriedPointBean"/>
<aop:aspectj-autoproxy/>
</beans>