From d765386e0569da713420d2bdb442c3633e814778 Mon Sep 17 00:00:00 2001 From: zhangxin10 Date: Tue, 29 Dec 2015 15:35:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DJavassist=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=B7=B2=E7=BB=8F=E8=A2=ABSpring=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E8=BF=87=E7=9A=84=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- skywalking-sdk-plugin/spring-plugin/pom.xml | 23 +- .../plugin/spring/TracingAspect.java | 34 +++ .../spring/TracingEnhanceProcessor.java | 264 +++--------------- .../plugin/spring/TracingPattern.java | 53 ++-- .../main/resources/META-INF/skywalking.xsd | 6 +- .../plugin/spring/test/TestBean.java | 6 +- .../test/resources/springConfig-common.xml | 10 +- 7 files changed, 123 insertions(+), 273 deletions(-) create mode 100644 skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingAspect.java diff --git a/skywalking-sdk-plugin/spring-plugin/pom.xml b/skywalking-sdk-plugin/spring-plugin/pom.xml index d799de1f9..cc82a5c24 100644 --- a/skywalking-sdk-plugin/spring-plugin/pom.xml +++ b/skywalking-sdk-plugin/spring-plugin/pom.xml @@ -25,10 +25,11 @@ - - org.javassist - javassist - 3.20.0-GA + + org.aspectj + aspectjweaver + 1.8.7 + compile com.ai.cloud @@ -39,7 +40,7 @@ junit junit 3.8.1 - compile + test org.springframework @@ -47,12 +48,6 @@ 3.2.0.RELEASE compile - - org.aspectj - aspectjweaver - 1.8.7 - test - com.ai.cloud skywalking-auth @@ -77,11 +72,7 @@ 2.1.1 test - - junit - junit - 4.12 - + mysql mysql-connector-java diff --git a/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingAspect.java b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingAspect.java new file mode 100644 index 000000000..34edc5e2b --- /dev/null +++ b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingAspect.java @@ -0,0 +1,34 @@ +package com.ai.cloud.skywalking.plugin.spring; + +import com.ai.cloud.skywalking.buriedpoint.LocalBuriedPointSender; +import com.ai.cloud.skywalking.model.Identification; +import org.aspectj.lang.ProceedingJoinPoint; + +public class TracingAspect { + + public Object doTracing(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { + LocalBuriedPointSender _sender = new LocalBuriedPointSender(); + try { + StringBuilder viewPoint = new StringBuilder(); + viewPoint.append(proceedingJoinPoint.getTarget().getClass().getName() + + "("); + boolean first = true; + for (Object arg : proceedingJoinPoint.getArgs()) { + if (!first) { + viewPoint.append(","); + } else { + first = false; + } + viewPoint.append(arg.getClass().getName()); + } + viewPoint.append(")"); + _sender.beforeSend(Identification.newBuilder().viewPoint(viewPoint.toString()).spanType("M").build()); + return proceedingJoinPoint.proceed(); + } catch (Throwable e) { + _sender.handleException(e); + throw e; + } finally { + _sender.afterSend(); + } + } +} 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 index 903a719e1..aa3373249 100644 --- 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 @@ -1,15 +1,12 @@ package com.ai.cloud.skywalking.plugin.spring; -import com.ai.cloud.skywalking.buriedpoint.LocalBuriedPointSender; import com.ai.cloud.skywalking.conf.AuthDesc; -import com.ai.cloud.skywalking.model.Identification; import com.ai.cloud.skywalking.plugin.spring.util.ConcurrentHashSet; - -import javassist.*; -import javassist.Modifier; -import javassist.bytecode.AnnotationsAttribute; -import javassist.bytecode.ConstPool; - +import org.springframework.aop.aspectj.AspectInstanceFactory; +import org.springframework.aop.aspectj.AspectJAroundAdvice; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; +import org.springframework.aop.aspectj.SimpleAspectInstanceFactory; +import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; @@ -18,21 +15,29 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import java.lang.reflect.*; import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; public class TracingEnhanceProcessor implements DisposableBean, BeanPostProcessor, BeanFactoryPostProcessor, ApplicationContextAware { - private static ClassPool pool = ClassPool.getDefault(); - private final Set beanSet = new ConcurrentHashSet(); @Override public void postProcessBeanFactory( ConfigurableListableBeanFactory beanFactory) throws BeansException { - beanSet.addAll(applicationContext.getBeansOfType(TracingPattern.class) - .values()); + for (TracingPattern tracingPattern : applicationContext.getBeansOfType(TracingPattern.class) + .values()) { + + AspectJExpressionPointcut packageMatcher = new AspectJExpressionPointcut(); + packageMatcher.setExpression("within(" + tracingPattern.getPackageExpression() + ")"); + tracingPattern.setPackageMatcher(packageMatcher); + + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression("execution(* " + tracingPattern.getPackageExpression().substring(0, tracingPattern.getPackageExpression().length() - 1) + tracingPattern.getClassExpression() + ".*(..))"); + tracingPattern.setPointcut(pointcut); + + beanSet.add(tracingPattern); + } + } @Override @@ -49,229 +54,36 @@ public class TracingEnhanceProcessor implements DisposableBean, this.applicationContext = applicationContext; } - public enum MatchType { - METHOD, PACKAGE, CLASS; - } - - private boolean checkMatch(String value, String pattern, MatchType matchType) { - boolean result; - if ("*".equals(pattern)) { - return true; - } - if (matchType == MatchType.PACKAGE) { - if (pattern.endsWith(".*")) { - String newPattern = pattern.substring(0, - pattern.lastIndexOf(".*")); - result = value.startsWith(newPattern); - } else { - result = value.equals(pattern); - } - } else { - if (pattern.endsWith("*")) { - String newPattern = pattern.substring(0, - pattern.lastIndexOf("*")); - result = value.startsWith(newPattern); - } else { - result = value.equals(pattern); - } - } - return result; - } - @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if(!AuthDesc.isAuth()){ - return bean; - } - - String packageName; - if (bean.getClass().getPackage() == null) { - packageName = ""; - } else { - packageName = bean.getClass().getPackage().getName(); - } - String className = bean.getClass().getSimpleName(); - TracingPattern matchClassBean = null; - boolean isMatch = false; - for (TracingPattern tracingPattern : beanSet) { - if (checkMatch(packageName, tracingPattern.getPackageName(), - MatchType.PACKAGE) - && checkMatch(className, tracingPattern.getClassName(), - MatchType.CLASS)) { - isMatch = true; - matchClassBean = tracingPattern; - continue; - } - } - if (!isMatch || matchClassBean == null) { + if (!AuthDesc.isAuth()) { return bean; } - // 符合规范 - try { - pool.appendClassPath(new ClassClassPath(bean.getClass())); - CtClass ctSource = pool.get(bean.getClass().getName()); - CtClass ctDestination = pool.makeClass( - generateProxyClassName(bean), ctSource); - for (CtClass interfaceCtClass : ctSource.getInterfaces()) { - ctDestination.addInterface(interfaceCtClass); + for (TracingPattern tracingPattern : beanSet) { + if (tracingPattern.getPackageMatcher().matches(bean.getClass()) && matchClassName(tracingPattern.getClassExpression(), bean + .getClass().getSimpleName())) { + ProxyFactory proxyFactory = new ProxyFactory(bean); + proxyFactory.setProxyTargetClass(true); + AspectInstanceFactory aspectInstanceFactory = new SimpleAspectInstanceFactory(TracingAspect.class); + AspectJAroundAdvice advised = new AspectJAroundAdvice(TracingAspect.class.getDeclaredMethods()[0], + tracingPattern.getPointcut(), aspectInstanceFactory); + proxyFactory.addAdvice(advised); + + return proxyFactory.getProxy(); } - // 拷贝所有的注解 - copyClassAnnotation(ctSource, ctDestination); - // 拷贝所有的方法,并增强 - ConstPool cp = ctDestination.getClassFile().getConstPool(); - for (CtMethod m : ctSource.getDeclaredMethods()) { - - if (m.getModifiers() == Modifier.PRIVATE) { - continue; - } - - CtMethod newm = CtNewMethod.delegator(m, ctDestination); - copyMethodAnnotation(cp, m, newm); - // 是否符合规范,符合则增强 - if (checkMatch(m.getName(), matchClassBean.getMethod(), - MatchType.METHOD)) { - enhanceMethod(bean, newm); - } - ctDestination.addMethod(newm); - } - - Class generateClass = ctDestination.toClass(); - Object newBean = generateClass.newInstance(); - Class currentClass = newBean.getClass().getSuperclass(); - Class valueClass = bean.getClass(); - Field tmpField = null; - while (true) { - if (currentClass.getName().equals(Object.class.getName())) { - break; - } - for (Field field : currentClass.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())){ - continue; - } - field.setAccessible(true); - tmpField = valueClass.getDeclaredField(field.getName()); - tmpField.setAccessible(true); - field.set(newBean, tmpField.get(bean)); - } - currentClass = currentClass.getSuperclass(); - valueClass = valueClass.getSuperclass(); - } - return newBean; - } catch (NotFoundException e) { - throw new IllegalStateException("Class [" - + beanName.getClass().getName() + "] cannot be found", e); - } catch (CannotCompileException e) { - throw new IllegalStateException("Class [" - + beanName.getClass().getName() + "] cannot be compile", e); - } catch (InstantiationException e) { - throw new IllegalStateException("Failed to instance class[" - + beanName.getClass().getName() + "]", e); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Failed to access class[" - + beanName.getClass().getName() + "]", e); - } catch (NoSuchFieldException e) { - throw new IllegalStateException("Failed to access class[" - + beanName.getClass().getName() + "]", e); } + return bean; } - private void copyMethodAnnotation(ConstPool cp, CtMethod m, CtMethod newm) { - AnnotationsAttribute invAnn = (AnnotationsAttribute) m.getMethodInfo() - .getAttribute(AnnotationsAttribute.invisibleTag); - AnnotationsAttribute visAnn = (AnnotationsAttribute) m.getMethodInfo() - .getAttribute(AnnotationsAttribute.visibleTag); - if (invAnn != null) { - newm.getMethodInfo().addAttribute(invAnn.copy(cp, null)); + private boolean matchClassName(String className, String simpleName) { + if ("*".equals(className)) { + return true; + } else if (className.endsWith("*")) { + return simpleName.startsWith(className); } - if (visAnn != null) { - newm.getMethodInfo().addAttribute(visAnn.copy(cp, null)); - } - } - - private String generateProxyClassName(Object bean) { - return bean.getClass().getName() + "$EnhanceBySWTracing$" - + ThreadLocalRandom.current().nextInt(100); - } - - private void copyAllFields(CtClass ctSource, CtClass ctDestination) - throws CannotCompileException, NotFoundException { - // copy fields - ConstPool cp = ctDestination.getClassFile().getConstPool(); - for (CtField ctSourceField : ctSource.getDeclaredFields()) { - CtClass fieldTypeClass = ClassPool.getDefault().get( - ctSourceField.getType().getName()); - CtField ctField = new CtField(fieldTypeClass, - ctSourceField.getName(), ctDestination); - // with annotations - copyAllFieldAnnotation(cp, ctSourceField, ctField); - ctDestination.addField(ctField); - } - } - - private void copyAllFieldAnnotation(ConstPool cp, CtField ctSourceField, - CtField ctDestinationField) throws CannotCompileException { - AnnotationsAttribute invAnn = (AnnotationsAttribute) ctSourceField - .getFieldInfo().getAttribute(AnnotationsAttribute.invisibleTag); - AnnotationsAttribute visAnn = (AnnotationsAttribute) ctSourceField - .getFieldInfo().getAttribute(AnnotationsAttribute.visibleTag); - - if (invAnn != null) { - ctDestinationField.getFieldInfo().addAttribute( - invAnn.copy(cp, null)); - } - if (visAnn != null) { - ctDestinationField.getFieldInfo().addAttribute( - visAnn.copy(cp, null)); - } - } - - private void copyClassAnnotation(CtClass ctSource, CtClass ctDestination) { - ConstPool cp = ctDestination.getClassFile().getConstPool(); - AnnotationsAttribute invAnn = (AnnotationsAttribute) ctSource - .getClassFile().getAttribute(AnnotationsAttribute.invisibleTag); - AnnotationsAttribute visAnn = (AnnotationsAttribute) ctSource - .getClassFile().getAttribute(AnnotationsAttribute.visibleTag); - if (invAnn != null) { - ctDestination.getClassFile().addAttribute(invAnn.copy(cp, null)); - } - if (visAnn != null) { - ctDestination.getClassFile().addAttribute(visAnn.copy(cp, null)); - } - } - - protected void enhanceMethod(Object bean, CtMethod method) - throws CannotCompileException, NotFoundException { - ClassPool cp = method.getDeclaringClass().getClassPool(); - method.addLocalVariable("___sender", - cp.get(LocalBuriedPointSender.class.getName())); - method.insertBefore("___sender = new " - + LocalBuriedPointSender.class.getName() - + "();\n___sender.beforeSend" - + generateBeforeSendParameter(bean, method) + "\n"); - method.addCatch("new " + LocalBuriedPointSender.class.getName() - + "().handleException(e);throw e;", ClassPool.getDefault() - .getCtClass(Throwable.class.getName()), "e"); - method.insertAfter("new " + LocalBuriedPointSender.class.getName() - + "().afterSend();", true); - } - - private String generateBeforeSendParameter(Object bean, CtMethod method) - throws NotFoundException { - StringBuilder builder = new StringBuilder("(" - + Identification.class.getName() + ".newBuilder().viewPoint(\"" - + bean.getClass().getName() + "." + method.getName()); - builder.append("("); - for (CtClass param : method.getParameterTypes()) { - builder.append(param.getSimpleName() + ","); - } - if (method.getParameterTypes().length > 0) { - builder = builder.delete(builder.length() - 1, builder.length()); - } - builder.append(")"); - builder.append("\").spanType(\"M\").build());"); - return builder.toString(); + return false; } @Override diff --git a/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingPattern.java b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingPattern.java index 7c5a4ba47..1ce807723 100644 --- a/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingPattern.java +++ b/skywalking-sdk-plugin/spring-plugin/src/main/java/com/ai/cloud/skywalking/plugin/spring/TracingPattern.java @@ -1,31 +1,42 @@ package com.ai.cloud.skywalking.plugin.spring; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; + public class TracingPattern { - private String packageName = ""; - private String className = ""; - private String method = ""; + private String packageExpression = ""; + private String classExpression = ""; + private AspectJExpressionPointcut packageMatcher; + private AspectJExpressionPointcut pointcut; - public String getPackageName() { - return packageName; - } + public String getPackageExpression() { + return packageExpression; + } - public void setPackageName(String packageName) { - this.packageName = packageName; - } + public void setPackageExpression(String packageExpression) { + this.packageExpression = packageExpression; + } - public String getClassName() { - return className; - } + public String getClassExpression() { + return classExpression; + } - public void setClassName(String className) { - this.className = className; - } + public void setClassExpression(String classExpression) { + this.classExpression = classExpression; + } - public String getMethod() { - return method; - } + public AspectJExpressionPointcut getPackageMatcher() { + return packageMatcher; + } - public void setMethod(String method) { - this.method = method; - } + public void setPackageMatcher(AspectJExpressionPointcut packageMatcher) { + this.packageMatcher = packageMatcher; + } + + public AspectJExpressionPointcut getPointcut() { + return pointcut; + } + + public void setPointcut(AspectJExpressionPointcut pointcut) { + this.pointcut = pointcut; + } } diff --git a/skywalking-sdk-plugin/spring-plugin/src/main/resources/META-INF/skywalking.xsd b/skywalking-sdk-plugin/spring-plugin/src/main/resources/META-INF/skywalking.xsd index 33d71997f..f0df02fe6 100644 --- a/skywalking-sdk-plugin/spring-plugin/src/main/resources/META-INF/skywalking.xsd +++ b/skywalking-sdk-plugin/spring-plugin/src/main/resources/META-INF/skywalking.xsd @@ -8,9 +8,7 @@ - - - + + \ No newline at end of file diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/test/TestBean.java b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/test/TestBean.java index a54b0a499..d728a6e77 100644 --- a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/test/TestBean.java +++ b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/test/TestBean.java @@ -6,13 +6,17 @@ import org.springframework.transaction.annotation.Transactional; @Service @Transactional -public class TestBean { +public class TestBean/* implements TestInterface*/ { private String value; public void testPrintln(String value) { System.out.println(value); } + private void testPrintln2(String value) { + System.out.println(value); + } + public static void main(String[] args) throws IllegalAccessException { ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath*:springConfig-common.xml"); 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 index 5eeb4bf5d..d1b13c94e 100644 --- a/skywalking-sdk-plugin/spring-plugin/src/test/resources/springConfig-common.xml +++ b/skywalking-sdk-plugin/spring-plugin/src/test/resources/springConfig-common.xml @@ -18,10 +18,10 @@ - - - - + + + + @@ -45,6 +45,6 @@ - + \ No newline at end of file