diff --git a/skywalking-sdk-plugin/spring-plugin/pom.xml b/skywalking-sdk-plugin/spring-plugin/pom.xml index 636685650..0a23bb992 100644 --- a/skywalking-sdk-plugin/spring-plugin/pom.xml +++ b/skywalking-sdk-plugin/spring-plugin/pom.xml @@ -34,36 +34,12 @@ 3.8.1 compile - - org.springframework - spring-beans - 3.2.0.RELEASE - compile - org.springframework spring-context 3.2.0.RELEASE compile - - org.springframework - spring-web - 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 @@ -76,21 +52,6 @@ ${project.version} test - - - - - - - - - - - - - - - junit junit 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 e0c03c75e..febf2ca3c 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 @@ -3,12 +3,10 @@ package com.ai.cloud.skywalking.plugin.spring; import com.ai.cloud.skywalking.buriedpoint.LocalBuriedPointSender; 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.beans.BeanUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; @@ -17,234 +15,261 @@ 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 { + BeanPostProcessor, BeanFactoryPostProcessor, ApplicationContextAware { - private final Set beanSet = new ConcurrentHashSet(); + private final Set beanSet = new ConcurrentHashSet(); - - @Override - public void postProcessBeanFactory( - ConfigurableListableBeanFactory beanFactory) throws BeansException { - beanSet.addAll(applicationContext.getBeansOfType(TracingPattern.class) - .values()); - } + @Override + public void postProcessBeanFactory( + ConfigurableListableBeanFactory beanFactory) throws BeansException { + beanSet.addAll(applicationContext.getBeansOfType(TracingPattern.class) + .values()); + } - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) - throws BeansException { - return bean; - } + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } - private ApplicationContext applicationContext; + private ApplicationContext applicationContext; - @Override - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - this.applicationContext = applicationContext; - } + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } - public enum MatchType { - METHOD, PACKAGE, CLASS; - } + 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; - } + 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 { - String 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) { - return bean; - } + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + 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) { + return bean; + } - // 符合规范 - try { - ClassPool pool = ClassPool.getDefault(); - CtClass ctSource = pool.get(bean.getClass().getName()); - CtClass ctDestination = pool.makeClass( - generateProxyClassName(bean), ctSource); - // 拷贝所有的方法, - copyAllFields(ctSource, ctDestination); - // 拷贝所有的注解 - 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); - } + // 符合规范 + try { + ClassPool pool = ClassPool.getDefault(); + 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); + } + // 拷贝所有的注解 + copyClassAnnotation(ctSource, ctDestination); + // 拷贝所有的方法,并增强 + ConstPool cp = ctDestination.getClassFile().getConstPool(); + for (CtMethod m : ctSource.getDeclaredMethods()) { - Class generateClass = ctDestination.toClass(); - Object newBean = generateClass.newInstance(); - BeanUtils.copyProperties(bean, newBean); - 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); - } - } + 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); + } - 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)); - } - if (visAnn != null) { - newm.getMethodInfo().addAttribute(visAnn.copy(cp, null)); - } - } + 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); + } + } - private String generateProxyClassName(Object bean) { - return bean.getClass().getName() + "$EnhanceBySWTracing$" - + ThreadLocalRandom.current().nextInt(100); - } + 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)); + } + if (visAnn != null) { + newm.getMethodInfo().addAttribute(visAnn.copy(cp, null)); + } + } - 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 String generateProxyClassName(Object bean) { + return bean.getClass().getName() + "$EnhanceBySWTracing$" + + ThreadLocalRandom.current().nextInt(100); + } - 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); + 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); + } + } - if (invAnn != null) { - ctDestinationField.getFieldInfo().addAttribute( - invAnn.copy(cp, null)); - } - if (visAnn != null) { - ctDestinationField.getFieldInfo().addAttribute( - visAnn.copy(cp, null)); - } - } + 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); - 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)); - } - } + if (invAnn != null) { + ctDestinationField.getFieldInfo().addAttribute( + invAnn.copy(cp, null)); + } + if (visAnn != null) { + ctDestinationField.getFieldInfo().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 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)); + } + } - 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(); - } + 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); + } - @Override - public void destroy() throws Exception { + 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(); + } + + @Override + public void destroy() throws Exception { + + } - } } diff --git a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/TestBean.java b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/TestBean.java index a39702fd7..96511be85 100644 --- a/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/TestBean.java +++ b/skywalking-sdk-plugin/spring-plugin/src/test/java/com/ai/cloud/skywalking/plugin/spring/TestBean.java @@ -3,15 +3,24 @@ package com.ai.cloud.skywalking.plugin.spring; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestBean { + private String value; - public void testPrintln(String value){ + public void testPrintln(String value) { System.out.println(value); } - public static void main(String[] args){ + public static void main(String[] args) throws IllegalAccessException { ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath*:springConfig-common.xml"); TestBean testBean = classPathXmlApplicationContext.getBean(TestBean.class); testBean.testPrintln("Hello World"); } -} \ No newline at end of file + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} 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 0d282ea61..56d9a7cfa 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 @@ -7,8 +7,10 @@ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://cloud.asiainfo.com/schema/skywalking http://cloud.asiainfo.com/schema/skywalking/skywalking.xsd"> - - - + + + + + \ No newline at end of file