diff --git a/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml b/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml index 9c73106af48c71018a92685c6984762b1be22388..f65696a35e8bc07bb0d34b219ac16ea346d12a0d 100644 --- a/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml +++ b/apm-collector/apm-collector-boot/src/main/assembly/log4j2.xml @@ -22,8 +22,8 @@ ${sys:collector.logDir} - + %d - %c -%-4r [%t] %-5p %x - %m%n diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/AutowiredAnnotationProcessorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/AutowiredAnnotationProcessorInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..3a6b48cf640fea2ca0748541333abf411e9b388f --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/AutowiredAnnotationProcessorInterceptor.java @@ -0,0 +1,109 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Project repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.spring.patch; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +/** + * {@link AutowiredAnnotationProcessorInterceptor} return the correct constructor when the bean class is enhanced by + * skywalking. + * + * @author zhangxin + */ +public class AutowiredAnnotationProcessorInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor { + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret) throws Throwable { + Class beanClass = (Class)allArguments[0]; + if (EnhancedInstance.class.isAssignableFrom(beanClass)) { + Map, Constructor[]> candidateConstructorsCache = (Map, Constructor[]>)objInst.getSkyWalkingDynamicField(); + + Constructor[] candidateConstructors = candidateConstructorsCache.get(beanClass); + if (candidateConstructors == null) { + Constructor[] returnCandidateConstructors = (Constructor[])ret; + + /** + * The return for the method {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors(Class, String) + * contains three cases: + * 1. Constructors with annotation {@link org.springframework.beans.factory.annotation.Autowired}. + * 2. The bean class only has one constructor with parameters. + * 3. The bean has constructor without parameters. + * + * because of the manipulate mechanism generates another private constructor in the enhance class, all the class that constrcutor enhance by skywalking + * cannot go to case two, and it will go to case three. case one is not affected in the current manipulate mechanism situation. + * + * The interceptor fill out the private constructor when the class is enhanced by skywalking, and check if the remainder constructors size is equals one, + * if yes, return the constructor. or return constructor without parameters. + * + * @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors(Class, String) + */ + if (returnCandidateConstructors == null) { + Constructor[] rawConstructor = beanClass.getDeclaredConstructors(); + List> candidateRawConstructors = new ArrayList>(); + for (Constructor constructor : rawConstructor) { + if (!Modifier.isPrivate(constructor.getModifiers())) { + candidateRawConstructors.add(constructor); + } + } + + if (candidateRawConstructors.size() == 1 && candidateRawConstructors.get(0).getParameterTypes().length > 0) { + candidateConstructors = new Constructor[] {candidateRawConstructors.get(0)}; + } else { + candidateConstructors = new Constructor[0]; + } + + } else { + candidateConstructors = returnCandidateConstructors; + } + + candidateConstructorsCache.put(beanClass, candidateConstructors); + } + + return candidateConstructors.length > 0 ? candidateConstructors : null; + } + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + + } + + @Override public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + Map, Constructor[]> candidateConstructorsCache = new ConcurrentHashMap, Constructor[]>(20); + objInst.setSkyWalkingDynamicField(candidateConstructorsCache); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/define/AutowiredAnnotationProcessorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/define/AutowiredAnnotationProcessorInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..6c26653dc0504cf5733675f420c6c05af7153b46 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/java/org/skywalking/apm/plugin/spring/patch/define/AutowiredAnnotationProcessorInstrumentation.java @@ -0,0 +1,79 @@ +/* + * Copyright 2017, OpenSkywalking Organization All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Project repository: https://github.com/OpenSkywalking/skywalking + */ + +package org.skywalking.apm.plugin.spring.patch.define; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + +/** + * {@link AutowiredAnnotationProcessorInstrumentation} indicates a spring core class patch for making sure the + * determineCandidateConstructors method in the class {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor} + * works in spring designed ways + * + * @author zhang xin + */ +public class AutowiredAnnotationProcessorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + private static final String ENHANCE_CLASS = "org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"; + private static final String ENHANCE_METHOD = "determineCandidateConstructors"; + private static final String INTERCEPTOR_CLASS = "org.skywalking.apm.plugin.spring.patch.AutowiredAnnotationProcessorInterceptor"; + + @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override public ElementMatcher getConstructorMatcher() { + return any(); + } + + @Override public String getConstructorInterceptor() { + return INTERCEPTOR_CLASS; + } + } + }; + } + + @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_METHOD); + } + + @Override public String getMethodsInterceptor() { + return INTERCEPTOR_CLASS; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override protected ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def index 5caefb1d6dd9a2c5663c61323f2356dcdae2eb94..2d8504014734ba6d05a83e13a70cb26f0de2236e 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/core-patch/src/main/resources/skywalking-plugin.def @@ -1 +1,2 @@ spring-core-patch=org.skywalking.apm.plugin.spring.patch.define.AopProxyFactoryInstrumentation +spring-core-patch=org.skywalking.apm.plugin.spring.patch.define.AutowiredAnnotationProcessorInstrumentation